curb 1.3.5 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +90 -13
- data/Rakefile +8 -3
- data/doc.rb +48 -8
- data/ext/curb.c +33 -0
- data/ext/curb.h +3 -3
- data/ext/curb_easy.c +1471 -87
- data/ext/curb_easy.h +26 -0
- data/ext/curb_errors.c +2 -0
- data/ext/curb_errors.h +1 -0
- data/ext/curb_multi.c +257 -130
- data/ext/curb_multi.h +1 -0
- data/ext/extconf.rb +12 -0
- data/lib/curl/download.rb +160 -0
- data/lib/curl/easy.rb +113 -13
- data/lib/curl/multi.rb +172 -39
- data/lib/curl.rb +471 -11
- data/tests/bug_poison.rb +29 -0
- data/tests/helper.rb +178 -1
- data/tests/io_select_less_scheduler_probe.rb +105 -0
- data/tests/tc_curl_download.rb +86 -0
- data/tests/tc_curl_easy.rb +77 -0
- data/tests/tc_curl_easy_resolve.rb +2 -0
- data/tests/tc_curl_maxfilesize.rb +201 -1
- data/tests/tc_curl_multi.rb +258 -0
- data/tests/tc_curl_native_coverage.rb +1 -0
- data/tests/tc_curl_network_policy.rb +1475 -0
- data/tests/tc_curl_protocols.rb +351 -0
- data/tests/tc_fiber_scheduler.rb +373 -4
- data/tests/tc_ftp_options.rb +58 -0
- data/tests/tc_gc_compact.rb +53 -0
- data/tests/tc_test_server_methods.rb +15 -0
- metadata +9 -2
data/ext/curb_easy.c
CHANGED
|
@@ -11,16 +11,36 @@
|
|
|
11
11
|
#include "curb_multi.h"
|
|
12
12
|
|
|
13
13
|
#include <errno.h>
|
|
14
|
+
#include <stdlib.h>
|
|
14
15
|
#include <string.h>
|
|
15
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
|
|
16
26
|
#include <strings.h>
|
|
17
27
|
#endif
|
|
18
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
|
|
36
|
+
|
|
19
37
|
extern VALUE mCurl;
|
|
20
38
|
|
|
21
39
|
static VALUE idCall;
|
|
22
40
|
static VALUE idJoin;
|
|
23
41
|
static VALUE rbstrAmp;
|
|
42
|
+
static ID idNetworkPolicyNone;
|
|
43
|
+
static ID idNetworkPolicyPublic;
|
|
24
44
|
|
|
25
45
|
#ifdef RDOC_NEVER_DEFINED
|
|
26
46
|
mCurl = rb_define_module("Curl");
|
|
@@ -44,9 +64,649 @@ static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
|
|
44
64
|
#endif
|
|
45
65
|
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list);
|
|
46
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);
|
|
47
68
|
|
|
48
69
|
/* ================== CURL HANDLER FUNCS ==============*/
|
|
49
70
|
|
|
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
|
+
|
|
50
710
|
static VALUE callback_exception(VALUE unused, VALUE exception) {
|
|
51
711
|
return Qfalse;
|
|
52
712
|
}
|
|
@@ -93,6 +753,20 @@ static VALUE with_easy_callback_active(ruby_curl_easy *rbce, VALUE (*func)(VALUE
|
|
|
93
753
|
return rb_ensure(func, arg, ensure_clear_easy_callback_active, (VALUE)rbce);
|
|
94
754
|
}
|
|
95
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
|
+
|
|
96
770
|
struct stream_read_call_args {
|
|
97
771
|
VALUE stream;
|
|
98
772
|
size_t read_bytes;
|
|
@@ -170,6 +844,30 @@ static int curl_seek_fail_result(void) {
|
|
|
170
844
|
#endif
|
|
171
845
|
}
|
|
172
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
|
+
|
|
173
871
|
/* Default body handler appends to easy.body_data buffer */
|
|
174
872
|
static size_t default_body_handler(char *stream,
|
|
175
873
|
size_t size,
|
|
@@ -178,6 +876,11 @@ static size_t default_body_handler(char *stream,
|
|
|
178
876
|
ruby_curl_easy *rbce = (ruby_curl_easy *)userdata;
|
|
179
877
|
size_t total = size * nmemb;
|
|
180
878
|
VALUE out = rb_easy_get("body_data");
|
|
879
|
+
|
|
880
|
+
if (ruby_curl_easy_body_limit_exceeded(rbce, total)) {
|
|
881
|
+
return 0;
|
|
882
|
+
}
|
|
883
|
+
|
|
181
884
|
if (NIL_P(out)) {
|
|
182
885
|
out = rb_easy_set("body_data", rb_str_buf_new(32768));
|
|
183
886
|
}
|
|
@@ -346,6 +1049,10 @@ static size_t proc_data_handler_body(char *stream,
|
|
|
346
1049
|
args.nmemb = nmemb;
|
|
347
1050
|
args.proc = rb_easy_get("body_proc");
|
|
348
1051
|
|
|
1052
|
+
if (ruby_curl_easy_body_limit_exceeded(rbce, size * nmemb)) {
|
|
1053
|
+
return 0;
|
|
1054
|
+
}
|
|
1055
|
+
|
|
349
1056
|
dispatch_args.rbce = rbce;
|
|
350
1057
|
dispatch_args.func = call_proc_data_handler_wrapped;
|
|
351
1058
|
dispatch_args.arg = (VALUE)&args;
|
|
@@ -480,6 +1187,7 @@ static int proc_debug_handler(CURL *curl,
|
|
|
480
1187
|
static void curl_easy_mark(void *ptr) {
|
|
481
1188
|
ruby_curl_easy *rbce = (ruby_curl_easy *)ptr;
|
|
482
1189
|
if (rbce) {
|
|
1190
|
+
if (!NIL_P(rbce->self)) { rb_gc_mark(rbce->self); }
|
|
483
1191
|
if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
|
|
484
1192
|
if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
|
|
485
1193
|
if (!NIL_P(rbce->callback_error)) { rb_gc_mark(rbce->callback_error); }
|
|
@@ -534,6 +1242,27 @@ static void ruby_curl_easy_clear_resolve_list(ruby_curl_easy *rbce) {
|
|
|
534
1242
|
rbce->curl_resolve = NULL;
|
|
535
1243
|
}
|
|
536
1244
|
|
|
1245
|
+
static void ruby_curl_easy_clear_connect_to_list(ruby_curl_easy *rbce) {
|
|
1246
|
+
if (!rbce || !rbce->curl_connect_to) {
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
#ifdef HAVE_CURLOPT_CONNECT_TO
|
|
1250
|
+
if (rbce->curl) {
|
|
1251
|
+
curl_easy_setopt(rbce->curl, CURLOPT_CONNECT_TO, NULL);
|
|
1252
|
+
}
|
|
1253
|
+
#endif
|
|
1254
|
+
curl_slist_free_all(rbce->curl_connect_to);
|
|
1255
|
+
rbce->curl_connect_to = NULL;
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
static void ruby_curl_easy_clear_setup_lists(ruby_curl_easy *rbce) {
|
|
1259
|
+
ruby_curl_easy_clear_headers_list(rbce);
|
|
1260
|
+
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
1261
|
+
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
1262
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
1263
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
537
1266
|
/* Legacy wrapper for external callers */
|
|
538
1267
|
void ruby_curl_easy_mark(ruby_curl_easy *rbce) {
|
|
539
1268
|
curl_easy_mark((void *)rbce);
|
|
@@ -590,6 +1319,9 @@ static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
|
590
1319
|
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
591
1320
|
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
592
1321
|
ruby_curl_easy_clear_resolve_list(rbce);
|
|
1322
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
1323
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
1324
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
593
1325
|
|
|
594
1326
|
if (rbce->curl) {
|
|
595
1327
|
/* disable any progress or debug events */
|
|
@@ -659,12 +1391,18 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
659
1391
|
rbce->opts = rb_hash_new();
|
|
660
1392
|
|
|
661
1393
|
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
1394
|
+
memset(rbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
662
1395
|
|
|
663
1396
|
rbce->self = Qnil;
|
|
664
1397
|
rbce->curl_headers = NULL;
|
|
665
1398
|
rbce->curl_proxy_headers = NULL;
|
|
666
1399
|
rbce->curl_ftp_commands = NULL;
|
|
667
1400
|
rbce->curl_resolve = NULL;
|
|
1401
|
+
rbce->curl_connect_to = NULL;
|
|
1402
|
+
rbce->network_allowed_cidr_rules = NULL;
|
|
1403
|
+
rbce->network_allowed_hosts = NULL;
|
|
1404
|
+
rbce->network_allowed_cidr_rule_count = 0;
|
|
1405
|
+
rbce->network_allowed_host_count = 0;
|
|
668
1406
|
|
|
669
1407
|
/* various-typed opts */
|
|
670
1408
|
rbce->local_port = 0;
|
|
@@ -689,6 +1427,7 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
689
1427
|
rbce->ftp_filemethod = -1;
|
|
690
1428
|
rbce->http_version = CURL_HTTP_VERSION_NONE;
|
|
691
1429
|
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
1430
|
+
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
692
1431
|
|
|
693
1432
|
/* bool opts */
|
|
694
1433
|
rbce->proxy_tunnel = 0;
|
|
@@ -705,6 +1444,12 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
705
1444
|
rbce->cookielist_engine_enabled = 0;
|
|
706
1445
|
rbce->ignore_content_length = 0;
|
|
707
1446
|
rbce->callback_active = 0;
|
|
1447
|
+
rbce->unsafe_destination_blocked = 0;
|
|
1448
|
+
rbce->allow_proxy = 0;
|
|
1449
|
+
rbce->allow_unix_socket = 0;
|
|
1450
|
+
rbce->forbid_reuse_set = 0;
|
|
1451
|
+
rbce->native_active = 0;
|
|
1452
|
+
rbce->forbid_reuse = 0;
|
|
708
1453
|
rbce->callback_error = Qnil;
|
|
709
1454
|
rbce->last_result = 0;
|
|
710
1455
|
}
|
|
@@ -837,10 +1582,18 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
837
1582
|
newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
|
|
838
1583
|
newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
|
|
839
1584
|
newrbce->curl_resolve = (rbce->curl_resolve) ? duplicate_curl_slist(rbce->curl_resolve) : NULL;
|
|
1585
|
+
newrbce->curl_connect_to = (rbce->curl_connect_to) ? duplicate_curl_slist(rbce->curl_connect_to) : NULL;
|
|
1586
|
+
newrbce->network_allowed_cidr_rules = NULL;
|
|
1587
|
+
newrbce->network_allowed_cidr_rule_count = 0;
|
|
1588
|
+
newrbce->network_allowed_hosts = NULL;
|
|
1589
|
+
newrbce->network_allowed_host_count = 0;
|
|
840
1590
|
|
|
841
1591
|
/* A cloned easy should not retain ownership reference to the original multi. */
|
|
842
1592
|
newrbce->multi = Qnil;
|
|
843
1593
|
newrbce->callback_error = Qnil;
|
|
1594
|
+
newrbce->unsafe_destination_blocked = 0;
|
|
1595
|
+
memset(newrbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
1596
|
+
newrbce->native_active = 0;
|
|
844
1597
|
|
|
845
1598
|
if (rbce->opts != Qnil) {
|
|
846
1599
|
newrbce->opts = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
@@ -889,6 +1642,10 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
889
1642
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
890
1643
|
}
|
|
891
1644
|
|
|
1645
|
+
if (rbce->native_active) {
|
|
1646
|
+
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle during native operation");
|
|
1647
|
+
}
|
|
1648
|
+
|
|
892
1649
|
ruby_curl_easy_free(rbce);
|
|
893
1650
|
|
|
894
1651
|
/* reinit the handle */
|
|
@@ -935,6 +1692,10 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
|
935
1692
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
936
1693
|
}
|
|
937
1694
|
|
|
1695
|
+
if (rbce->native_active) {
|
|
1696
|
+
rb_raise(rb_eRuntimeError, "Cannot reset an active curl handle during native operation");
|
|
1697
|
+
}
|
|
1698
|
+
|
|
938
1699
|
opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
939
1700
|
|
|
940
1701
|
ruby_curl_easy_cleanup(self, rbce);
|
|
@@ -1281,7 +2042,17 @@ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
|
|
|
1281
2042
|
*
|
|
1282
2043
|
* This is handy if you want to perform a POST against a Curl::Multi instance.
|
|
1283
2044
|
*/
|
|
1284
|
-
|
|
2045
|
+
struct post_body_set_args {
|
|
2046
|
+
VALUE self;
|
|
2047
|
+
VALUE post_body;
|
|
2048
|
+
int force_http_get_on_nil;
|
|
2049
|
+
};
|
|
2050
|
+
|
|
2051
|
+
static VALUE ruby_curl_easy_post_body_set_with_mode_body(VALUE argp) {
|
|
2052
|
+
struct post_body_set_args *args = (struct post_body_set_args *)argp;
|
|
2053
|
+
VALUE self = args->self;
|
|
2054
|
+
VALUE post_body = args->post_body;
|
|
2055
|
+
int force_http_get_on_nil = args->force_http_get_on_nil;
|
|
1285
2056
|
ruby_curl_easy *rbce;
|
|
1286
2057
|
CURL *curl;
|
|
1287
2058
|
|
|
@@ -1345,6 +2116,17 @@ static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body,
|
|
|
1345
2116
|
return Qnil;
|
|
1346
2117
|
}
|
|
1347
2118
|
|
|
2119
|
+
static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body, int force_http_get_on_nil) {
|
|
2120
|
+
ruby_curl_easy *rbce;
|
|
2121
|
+
struct post_body_set_args args = { self, post_body, force_http_get_on_nil };
|
|
2122
|
+
|
|
2123
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2124
|
+
ruby_curl_easy_enter_native(rbce);
|
|
2125
|
+
|
|
2126
|
+
return rb_ensure(ruby_curl_easy_post_body_set_with_mode_body, (VALUE)&args,
|
|
2127
|
+
ruby_curl_easy_leave_native, (VALUE)rbce);
|
|
2128
|
+
}
|
|
2129
|
+
|
|
1348
2130
|
static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
|
|
1349
2131
|
return ruby_curl_easy_post_body_set_with_mode(self, post_body, 1);
|
|
1350
2132
|
}
|
|
@@ -1510,6 +2292,147 @@ static VALUE ruby_curl_easy_resolve_get(VALUE self) {
|
|
|
1510
2292
|
CURB_OBJECT_HGETTER(ruby_curl_easy, resolve);
|
|
1511
2293
|
}
|
|
1512
2294
|
|
|
2295
|
+
/*
|
|
2296
|
+
* call-seq:
|
|
2297
|
+
* easy.connect_to = [ "example.com:80:127.0.0.1:80" ] => [ "example.com:80:127.0.0.1:80" ]
|
|
2298
|
+
*
|
|
2299
|
+
* Set the connect-to list to redirect matching request host/port pairs to
|
|
2300
|
+
* alternate connection host/port pairs.
|
|
2301
|
+
*/
|
|
2302
|
+
static VALUE ruby_curl_easy_connect_to_set(VALUE self, VALUE connect_to) {
|
|
2303
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, connect_to);
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
/*
|
|
2307
|
+
* call-seq:
|
|
2308
|
+
* easy.connect_to => array or nil
|
|
2309
|
+
*/
|
|
2310
|
+
static VALUE ruby_curl_easy_connect_to_get(VALUE self) {
|
|
2311
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, connect_to);
|
|
2312
|
+
}
|
|
2313
|
+
|
|
2314
|
+
/*
|
|
2315
|
+
* call-seq:
|
|
2316
|
+
* easy.doh_url = "https://dns.example/dns-query" => "https://dns.example/dns-query"
|
|
2317
|
+
*
|
|
2318
|
+
* Set the DNS-over-HTTPS URL to use for resolving hostnames.
|
|
2319
|
+
*/
|
|
2320
|
+
static VALUE ruby_curl_easy_doh_url_set(VALUE self, VALUE doh_url) {
|
|
2321
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, doh_url);
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
/*
|
|
2325
|
+
* call-seq:
|
|
2326
|
+
* easy.doh_url => string or nil
|
|
2327
|
+
*/
|
|
2328
|
+
static VALUE ruby_curl_easy_doh_url_get(VALUE self) {
|
|
2329
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, doh_url);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
2333
|
+
/*
|
|
2334
|
+
* call-seq:
|
|
2335
|
+
* easy.dns_servers => string or nil
|
|
2336
|
+
*/
|
|
2337
|
+
static VALUE ruby_curl_easy_dns_servers_get(VALUE self) {
|
|
2338
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, dns_servers);
|
|
2339
|
+
}
|
|
2340
|
+
#endif
|
|
2341
|
+
|
|
2342
|
+
static VALUE ruby_curl_easy_allow_unix_socket_set(VALUE self, VALUE allow) {
|
|
2343
|
+
ruby_curl_easy *rbce;
|
|
2344
|
+
|
|
2345
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2346
|
+
rbce->allow_unix_socket = RTEST(allow) ? 1 : 0;
|
|
2347
|
+
|
|
2348
|
+
return allow;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
static VALUE ruby_curl_easy_allow_proxy_set(VALUE self, VALUE allow) {
|
|
2352
|
+
ruby_curl_easy *rbce;
|
|
2353
|
+
|
|
2354
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2355
|
+
rbce->allow_proxy = RTEST(allow) ? 1 : 0;
|
|
2356
|
+
|
|
2357
|
+
return allow;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2360
|
+
/*
|
|
2361
|
+
* call-seq:
|
|
2362
|
+
* easy.allowed_cidrs = ["203.0.113.0/24"] => ["203.0.113.0/24"]
|
|
2363
|
+
*
|
|
2364
|
+
* Set resolved-peer CIDR ranges that are allowed when network_policy is :public.
|
|
2365
|
+
* Private/local unsafe ranges are still blocked before this allowlist is
|
|
2366
|
+
* evaluated.
|
|
2367
|
+
*/
|
|
2368
|
+
static VALUE ruby_curl_easy_allowed_cidrs_set(VALUE self, VALUE cidrs) {
|
|
2369
|
+
ruby_curl_easy *rbce;
|
|
2370
|
+
VALUE normalized;
|
|
2371
|
+
VALUE stored;
|
|
2372
|
+
|
|
2373
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2374
|
+
normalized = curb_normalize_cidr_list(cidrs);
|
|
2375
|
+
stored = curb_dup_string_array(normalized);
|
|
2376
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_cidrs"), stored);
|
|
2377
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC) {
|
|
2378
|
+
curb_prepare_network_allowed_cidr_rules(rbce);
|
|
2379
|
+
} else {
|
|
2380
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
2381
|
+
}
|
|
2382
|
+
|
|
2383
|
+
return curb_dup_string_array(stored);
|
|
2384
|
+
}
|
|
2385
|
+
|
|
2386
|
+
/*
|
|
2387
|
+
* call-seq:
|
|
2388
|
+
* easy.allowed_cidrs => array or nil
|
|
2389
|
+
*/
|
|
2390
|
+
static VALUE ruby_curl_easy_allowed_cidrs_get(VALUE self) {
|
|
2391
|
+
ruby_curl_easy *rbce;
|
|
2392
|
+
VALUE cidrs;
|
|
2393
|
+
|
|
2394
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2395
|
+
cidrs = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_cidrs"));
|
|
2396
|
+
|
|
2397
|
+
return curb_dup_string_array(cidrs);
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
/*
|
|
2401
|
+
* call-seq:
|
|
2402
|
+
* easy.allowed_hosts = ["api.example.com"] => ["api.example.com"]
|
|
2403
|
+
*
|
|
2404
|
+
* Set URL hosts allowed for this handle. When libcurl supports
|
|
2405
|
+
* CURLOPT_PREREQFUNCTION, this is checked before each request, including
|
|
2406
|
+
* followed redirects.
|
|
2407
|
+
*/
|
|
2408
|
+
static VALUE ruby_curl_easy_allowed_hosts_set(VALUE self, VALUE hosts) {
|
|
2409
|
+
ruby_curl_easy *rbce;
|
|
2410
|
+
VALUE normalized;
|
|
2411
|
+
VALUE stored;
|
|
2412
|
+
|
|
2413
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2414
|
+
normalized = curb_normalize_host_list(hosts);
|
|
2415
|
+
stored = curb_dup_string_array(normalized);
|
|
2416
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("allowed_hosts"), stored);
|
|
2417
|
+
curb_prepare_network_allowed_hosts(rbce);
|
|
2418
|
+
|
|
2419
|
+
return curb_dup_string_array(stored);
|
|
2420
|
+
}
|
|
2421
|
+
|
|
2422
|
+
/*
|
|
2423
|
+
* call-seq:
|
|
2424
|
+
* easy.allowed_hosts => array or nil
|
|
2425
|
+
*/
|
|
2426
|
+
static VALUE ruby_curl_easy_allowed_hosts_get(VALUE self) {
|
|
2427
|
+
ruby_curl_easy *rbce;
|
|
2428
|
+
VALUE hosts;
|
|
2429
|
+
|
|
2430
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2431
|
+
hosts = rb_hash_aref(rbce->opts, rb_easy_hkey("allowed_hosts"));
|
|
2432
|
+
|
|
2433
|
+
return curb_dup_string_array(hosts);
|
|
2434
|
+
}
|
|
2435
|
+
|
|
1513
2436
|
/* ================== IMMED ATTRS ==================*/
|
|
1514
2437
|
|
|
1515
2438
|
/*
|
|
@@ -2458,41 +3381,136 @@ static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
|
|
|
2458
3381
|
|
|
2459
3382
|
/*
|
|
2460
3383
|
* call-seq:
|
|
2461
|
-
* easy.resolve_mode = symbol => symbol
|
|
2462
|
-
*
|
|
2463
|
-
* Configures what type of IP address this Curl::Easy instance
|
|
2464
|
-
* resolves DNS names to. Valid options are:
|
|
3384
|
+
* easy.resolve_mode = symbol => symbol
|
|
3385
|
+
*
|
|
3386
|
+
* Configures what type of IP address this Curl::Easy instance
|
|
3387
|
+
* resolves DNS names to. Valid options are:
|
|
3388
|
+
*
|
|
3389
|
+
* [:auto] resolves DNS names to all IP versions your system allows
|
|
3390
|
+
* [:ipv4] resolves DNS names to IPv4 only
|
|
3391
|
+
* [:ipv6] resolves DNS names to IPv6 only
|
|
3392
|
+
*/
|
|
3393
|
+
static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
3394
|
+
if (TYPE(resolve_mode) != T_SYMBOL) {
|
|
3395
|
+
rb_raise(rb_eTypeError, "Must pass a symbol");
|
|
3396
|
+
return Qnil;
|
|
3397
|
+
} else {
|
|
3398
|
+
ruby_curl_easy *rbce;
|
|
3399
|
+
ID resolve_mode_id;
|
|
3400
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3401
|
+
|
|
3402
|
+
resolve_mode_id = rb_to_id(resolve_mode);
|
|
3403
|
+
|
|
3404
|
+
if (resolve_mode_id == rb_intern("auto")) {
|
|
3405
|
+
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
3406
|
+
return resolve_mode;
|
|
3407
|
+
} else if (resolve_mode_id == rb_intern("ipv4")) {
|
|
3408
|
+
rbce->resolve_mode = CURL_IPRESOLVE_V4;
|
|
3409
|
+
return resolve_mode;
|
|
3410
|
+
} else if (resolve_mode_id == rb_intern("ipv6")) {
|
|
3411
|
+
rbce->resolve_mode = CURL_IPRESOLVE_V6;
|
|
3412
|
+
return resolve_mode;
|
|
3413
|
+
} else {
|
|
3414
|
+
rb_raise(rb_eArgError, "Must set to one of :auto, :ipv4, :ipv6");
|
|
3415
|
+
return Qnil;
|
|
3416
|
+
}
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3419
|
+
|
|
3420
|
+
/*
|
|
3421
|
+
* call-seq:
|
|
3422
|
+
* easy.network_policy => symbol
|
|
3423
|
+
*
|
|
3424
|
+
* Determine which native network policy will be enforced when libcurl opens
|
|
3425
|
+
* sockets for this handle.
|
|
3426
|
+
*/
|
|
3427
|
+
static VALUE ruby_curl_easy_network_policy_get(VALUE self) {
|
|
3428
|
+
ruby_curl_easy *rbce;
|
|
3429
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3430
|
+
|
|
3431
|
+
switch (rbce->network_policy) {
|
|
3432
|
+
case CURB_NETWORK_POLICY_PUBLIC:
|
|
3433
|
+
return ID2SYM(idNetworkPolicyPublic);
|
|
3434
|
+
case CURB_NETWORK_POLICY_NONE:
|
|
3435
|
+
default:
|
|
3436
|
+
return ID2SYM(idNetworkPolicyNone);
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
|
|
3440
|
+
/*
|
|
3441
|
+
* call-seq:
|
|
3442
|
+
* easy.network_policy = symbol => symbol
|
|
3443
|
+
*
|
|
3444
|
+
* Supported values:
|
|
3445
|
+
* [:none] disables native destination checks.
|
|
3446
|
+
* [:public] blocks loopback, private, link-local, multicast,
|
|
3447
|
+
* unspecified, metadata, and other non-public addresses.
|
|
3448
|
+
*/
|
|
3449
|
+
static VALUE ruby_curl_easy_network_policy_set(VALUE self, VALUE network_policy) {
|
|
3450
|
+
ruby_curl_easy *rbce;
|
|
3451
|
+
ID network_policy_id;
|
|
3452
|
+
|
|
3453
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3454
|
+
|
|
3455
|
+
if (NIL_P(network_policy)) {
|
|
3456
|
+
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
3457
|
+
return ID2SYM(idNetworkPolicyNone);
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3460
|
+
if (TYPE(network_policy) != T_SYMBOL) {
|
|
3461
|
+
rb_raise(rb_eTypeError, "network_policy must be a Symbol");
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
network_policy_id = rb_to_id(network_policy);
|
|
3465
|
+
|
|
3466
|
+
if (network_policy_id == idNetworkPolicyNone) {
|
|
3467
|
+
rbce->network_policy = CURB_NETWORK_POLICY_NONE;
|
|
3468
|
+
rbce->allow_proxy = 0;
|
|
3469
|
+
return network_policy;
|
|
3470
|
+
} else if (network_policy_id == idNetworkPolicyPublic) {
|
|
3471
|
+
#ifndef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
3472
|
+
rb_raise(rb_eNotImpError, "network_policy=:public requires CURLOPT_OPENSOCKETFUNCTION support");
|
|
3473
|
+
#else
|
|
3474
|
+
rbce->network_policy = CURB_NETWORK_POLICY_PUBLIC;
|
|
3475
|
+
rbce->allow_proxy = 0;
|
|
3476
|
+
return network_policy;
|
|
3477
|
+
#endif
|
|
3478
|
+
}
|
|
3479
|
+
|
|
3480
|
+
rb_raise(rb_eArgError, "network_policy must be one of :none, :public");
|
|
3481
|
+
}
|
|
3482
|
+
|
|
3483
|
+
/*
|
|
3484
|
+
* call-seq:
|
|
3485
|
+
* easy.unsafe_destination_error => string or nil
|
|
3486
|
+
*
|
|
3487
|
+
* Return the native network policy block reason from the most recent transfer.
|
|
3488
|
+
*/
|
|
3489
|
+
static VALUE ruby_curl_easy_unsafe_destination_error_get(VALUE self) {
|
|
3490
|
+
ruby_curl_easy *rbce;
|
|
3491
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3492
|
+
|
|
3493
|
+
if (rbce->unsafe_destination_blocked && rbce->unsafe_destination_error[0]) {
|
|
3494
|
+
return rb_str_new2(rbce->unsafe_destination_error);
|
|
3495
|
+
}
|
|
3496
|
+
|
|
3497
|
+
return Qnil;
|
|
3498
|
+
}
|
|
3499
|
+
|
|
3500
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
3501
|
+
/*
|
|
3502
|
+
* call-seq:
|
|
3503
|
+
* easy.unix_socket_path => string or nil
|
|
2465
3504
|
*
|
|
2466
|
-
*
|
|
2467
|
-
* [:ipv4] resolves DNS names to IPv4 only
|
|
2468
|
-
* [:ipv6] resolves DNS names to IPv6 only
|
|
3505
|
+
* Return the configured Unix socket path, if set through CURLOPT_UNIX_SOCKET_PATH.
|
|
2469
3506
|
*/
|
|
2470
|
-
static VALUE
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
return Qnil;
|
|
2474
|
-
} else {
|
|
2475
|
-
ruby_curl_easy *rbce;
|
|
2476
|
-
ID resolve_mode_id;
|
|
2477
|
-
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2478
|
-
|
|
2479
|
-
resolve_mode_id = rb_to_id(resolve_mode);
|
|
3507
|
+
static VALUE ruby_curl_easy_unix_socket_path_get(VALUE self) {
|
|
3508
|
+
ruby_curl_easy *rbce;
|
|
3509
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2480
3510
|
|
|
2481
|
-
|
|
2482
|
-
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
2483
|
-
return resolve_mode;
|
|
2484
|
-
} else if (resolve_mode_id == rb_intern("ipv4")) {
|
|
2485
|
-
rbce->resolve_mode = CURL_IPRESOLVE_V4;
|
|
2486
|
-
return resolve_mode;
|
|
2487
|
-
} else if (resolve_mode_id == rb_intern("ipv6")) {
|
|
2488
|
-
rbce->resolve_mode = CURL_IPRESOLVE_V6;
|
|
2489
|
-
return resolve_mode;
|
|
2490
|
-
} else {
|
|
2491
|
-
rb_raise(rb_eArgError, "Must set to one of :auto, :ipv4, :ipv6");
|
|
2492
|
-
return Qnil;
|
|
2493
|
-
}
|
|
2494
|
-
}
|
|
3511
|
+
return rb_easy_get("unix_socket_path");
|
|
2495
3512
|
}
|
|
3513
|
+
#endif
|
|
2496
3514
|
|
|
2497
3515
|
/*
|
|
2498
3516
|
* call-seq:
|
|
@@ -2802,13 +3820,32 @@ static VALUE cb_each_resolve(VALUE resolve, VALUE wrap, int _c, const VALUE *_pt
|
|
|
2802
3820
|
return resolve_string;
|
|
2803
3821
|
}
|
|
2804
3822
|
|
|
3823
|
+
/***********************************************
|
|
3824
|
+
* This is an rb_iterate callback used to set up the connect-to list.
|
|
3825
|
+
*/
|
|
3826
|
+
static VALUE cb_each_connect_to(VALUE connect_to, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
3827
|
+
struct curl_slist **list;
|
|
3828
|
+
VALUE connect_to_string;
|
|
3829
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
3830
|
+
|
|
3831
|
+
connect_to_string = rb_obj_as_string(connect_to);
|
|
3832
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(connect_to_string));
|
|
3833
|
+
if (!new_list) {
|
|
3834
|
+
rb_raise(rb_eNoMemError, "Failed to append to connect-to list");
|
|
3835
|
+
}
|
|
3836
|
+
*list = new_list;
|
|
3837
|
+
|
|
3838
|
+
return connect_to_string;
|
|
3839
|
+
}
|
|
3840
|
+
|
|
2805
3841
|
/***********************************************
|
|
2806
3842
|
*
|
|
2807
3843
|
* Setup a connection
|
|
2808
3844
|
*
|
|
2809
3845
|
* Always returns Qtrue, rb_raise on error.
|
|
2810
3846
|
*/
|
|
2811
|
-
VALUE
|
|
3847
|
+
static VALUE ruby_curl_easy_setup_body(VALUE arg) {
|
|
3848
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
2812
3849
|
// TODO this could do with a bit of refactoring...
|
|
2813
3850
|
CURL *curl;
|
|
2814
3851
|
VALUE url, _url = rb_easy_get("url");
|
|
@@ -2816,9 +3853,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2816
3853
|
struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
|
|
2817
3854
|
struct curl_slist **cmds = &(rbce->curl_ftp_commands);
|
|
2818
3855
|
struct curl_slist **rslv = &(rbce->curl_resolve);
|
|
3856
|
+
struct curl_slist **cnto = &(rbce->curl_connect_to);
|
|
3857
|
+
int public_policy_disables_proxy;
|
|
2819
3858
|
|
|
2820
3859
|
curl = rbce->curl;
|
|
3860
|
+
public_policy_disables_proxy = rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC && !rbce->allow_proxy;
|
|
2821
3861
|
rbce->callback_error = Qnil;
|
|
3862
|
+
rbce->unsafe_destination_blocked = 0;
|
|
3863
|
+
memset(rbce->unsafe_destination_error, 0, CURL_ERROR_SIZE);
|
|
2822
3864
|
|
|
2823
3865
|
if (_url == Qnil) {
|
|
2824
3866
|
rb_raise(eCurlErrError, "No URL supplied");
|
|
@@ -2827,6 +3869,60 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2827
3869
|
url = rb_check_string_type(_url);
|
|
2828
3870
|
curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
|
|
2829
3871
|
|
|
3872
|
+
#ifdef HAVE_CURLOPT_DOH_URL
|
|
3873
|
+
curl_easy_setopt(curl, CURLOPT_DOH_URL, rb_easy_nil("doh_url") ? NULL : rb_easy_get_str("doh_url"));
|
|
3874
|
+
#endif
|
|
3875
|
+
|
|
3876
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
3877
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC && !rb_easy_nil("dns_servers")) {
|
|
3878
|
+
rb_raise(eCurlErrUnsafeDestination, "DNS server overrides are disabled by public network policy");
|
|
3879
|
+
}
|
|
3880
|
+
curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, rb_easy_nil("dns_servers") ? NULL : rb_easy_get_str("dns_servers"));
|
|
3881
|
+
#endif
|
|
3882
|
+
|
|
3883
|
+
#ifdef CURB_HAVE_PREREQ_HOST_POLICY
|
|
3884
|
+
if (!rb_easy_nil("allowed_hosts")) {
|
|
3885
|
+
curb_prepare_network_allowed_hosts(rbce);
|
|
3886
|
+
curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, curb_host_allowlist_prereq);
|
|
3887
|
+
curl_easy_setopt(curl, CURLOPT_PREREQDATA, rbce);
|
|
3888
|
+
} else {
|
|
3889
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
3890
|
+
curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, NULL);
|
|
3891
|
+
curl_easy_setopt(curl, CURLOPT_PREREQDATA, NULL);
|
|
3892
|
+
}
|
|
3893
|
+
#else
|
|
3894
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
3895
|
+
#endif
|
|
3896
|
+
|
|
3897
|
+
#ifdef CURB_HAVE_OPENSOCKET_NETWORK_POLICY
|
|
3898
|
+
if (rbce->network_policy == CURB_NETWORK_POLICY_PUBLIC) {
|
|
3899
|
+
curb_prepare_network_allowed_cidr_rules(rbce);
|
|
3900
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, curb_public_network_opensocket);
|
|
3901
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, rbce);
|
|
3902
|
+
#ifdef HAVE_CURLOPT_FRESH_CONNECT
|
|
3903
|
+
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1L);
|
|
3904
|
+
#endif
|
|
3905
|
+
#ifdef HAVE_CURLOPT_FORBID_REUSE
|
|
3906
|
+
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, 1L);
|
|
3907
|
+
#endif
|
|
3908
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
3909
|
+
if (!rbce->allow_unix_socket) {
|
|
3910
|
+
curl_easy_setopt(curl, CURLOPT_UNIX_SOCKET_PATH, NULL);
|
|
3911
|
+
}
|
|
3912
|
+
#endif
|
|
3913
|
+
} else {
|
|
3914
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
3915
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, NULL);
|
|
3916
|
+
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, NULL);
|
|
3917
|
+
#ifdef HAVE_CURLOPT_FRESH_CONNECT
|
|
3918
|
+
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 0L);
|
|
3919
|
+
#endif
|
|
3920
|
+
#ifdef HAVE_CURLOPT_FORBID_REUSE
|
|
3921
|
+
curl_easy_setopt(curl, CURLOPT_FORBID_REUSE, rbce->forbid_reuse_set ? rbce->forbid_reuse : 0L);
|
|
3922
|
+
#endif
|
|
3923
|
+
}
|
|
3924
|
+
#endif
|
|
3925
|
+
|
|
2830
3926
|
// network stuff and auth
|
|
2831
3927
|
if (!rb_easy_nil("interface_hm")) {
|
|
2832
3928
|
curl_easy_setopt(curl, CURLOPT_INTERFACE, rb_easy_get_str("interface_hm"));
|
|
@@ -2858,13 +3954,17 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2858
3954
|
curl_easy_setopt(curl, CURLOPT_USERPWD, NULL);
|
|
2859
3955
|
}
|
|
2860
3956
|
|
|
2861
|
-
if (
|
|
3957
|
+
if (public_policy_disables_proxy) {
|
|
3958
|
+
curl_easy_setopt(curl, CURLOPT_PROXY, "");
|
|
3959
|
+
} else if (rb_easy_nil("proxy_url")) {
|
|
2862
3960
|
curl_easy_setopt(curl, CURLOPT_PROXY, NULL);
|
|
2863
3961
|
} else {
|
|
2864
3962
|
curl_easy_setopt(curl, CURLOPT_PROXY, rb_easy_get_str("proxy_url"));
|
|
2865
3963
|
}
|
|
2866
3964
|
|
|
2867
|
-
if (
|
|
3965
|
+
if (public_policy_disables_proxy) {
|
|
3966
|
+
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
|
|
3967
|
+
} else if (rb_easy_nil("proxypwd")) {
|
|
2868
3968
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, NULL);
|
|
2869
3969
|
} else {
|
|
2870
3970
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
|
|
@@ -2879,6 +3979,8 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2879
3979
|
#endif
|
|
2880
3980
|
|
|
2881
3981
|
// body/header procs
|
|
3982
|
+
rbce->downloaded_body_bytes = 0;
|
|
3983
|
+
|
|
2882
3984
|
if (!rb_easy_nil("body_proc")) {
|
|
2883
3985
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
|
|
2884
3986
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
|
|
@@ -2949,7 +4051,8 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2949
4051
|
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
2950
4052
|
#endif
|
|
2951
4053
|
|
|
2952
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL,
|
|
4054
|
+
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL,
|
|
4055
|
+
public_policy_disables_proxy ? 0L : rbce->proxy_tunnel);
|
|
2953
4056
|
curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
|
|
2954
4057
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, rbce->ssl_verify_peer);
|
|
2955
4058
|
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, rbce->ssl_verify_host);
|
|
@@ -3112,6 +4215,11 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
3112
4215
|
curl_easy_setopt(curl, CURLOPT_USERAGENT, rb_easy_get_str("useragent"));
|
|
3113
4216
|
}
|
|
3114
4217
|
|
|
4218
|
+
/* Setup can be rerun for safety-policy changes while a handle is attached.
|
|
4219
|
+
* Rebuild slist-backed options from Ruby opts instead of appending to stale
|
|
4220
|
+
* native lists. */
|
|
4221
|
+
ruby_curl_easy_clear_setup_lists(rbce);
|
|
4222
|
+
|
|
3115
4223
|
/* Setup HTTP headers if necessary */
|
|
3116
4224
|
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
|
3117
4225
|
|
|
@@ -3189,8 +4297,44 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
3189
4297
|
}
|
|
3190
4298
|
#endif
|
|
3191
4299
|
|
|
4300
|
+
#ifdef HAVE_CURLOPT_CONNECT_TO
|
|
4301
|
+
/* Setup connect-to list if necessary */
|
|
4302
|
+
if (!rb_easy_nil("connect_to")) {
|
|
4303
|
+
if (rb_easy_type_check("connect_to", T_ARRAY)) {
|
|
4304
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, cnto);
|
|
4305
|
+
rb_block_call(rb_easy_get("connect_to"), rb_intern("each"), 0, NULL, cb_each_connect_to, wrap);
|
|
4306
|
+
} else {
|
|
4307
|
+
VALUE connect_to_str = rb_obj_as_string(rb_easy_get("connect_to"));
|
|
4308
|
+
struct curl_slist *new_list = curl_slist_append(*cnto, StringValuePtr(connect_to_str));
|
|
4309
|
+
if (!new_list) {
|
|
4310
|
+
rb_raise(rb_eNoMemError, "Failed to append to connect-to list");
|
|
4311
|
+
}
|
|
4312
|
+
*cnto = new_list;
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4315
|
+
if (*cnto) {
|
|
4316
|
+
curl_easy_setopt(curl, CURLOPT_CONNECT_TO, *cnto);
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
#endif
|
|
4320
|
+
|
|
3192
4321
|
return Qnil;
|
|
3193
4322
|
}
|
|
4323
|
+
|
|
4324
|
+
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
4325
|
+
ruby_curl_easy_enter_native(rbce);
|
|
4326
|
+
return rb_ensure(ruby_curl_easy_setup_body, (VALUE)rbce,
|
|
4327
|
+
ruby_curl_easy_leave_native, (VALUE)rbce);
|
|
4328
|
+
}
|
|
4329
|
+
|
|
4330
|
+
static VALUE ruby_curl_easy_setup_self(VALUE self) {
|
|
4331
|
+
ruby_curl_easy *rbce;
|
|
4332
|
+
|
|
4333
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4334
|
+
ruby_curl_easy_setup(rbce);
|
|
4335
|
+
|
|
4336
|
+
return self;
|
|
4337
|
+
}
|
|
3194
4338
|
/***********************************************
|
|
3195
4339
|
*
|
|
3196
4340
|
* Clean up a connection
|
|
@@ -3202,6 +4346,7 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
|
3202
4346
|
CURL *curl = rbce->curl;
|
|
3203
4347
|
struct curl_slist *ftp_commands;
|
|
3204
4348
|
struct curl_slist *resolve;
|
|
4349
|
+
struct curl_slist *connect_to;
|
|
3205
4350
|
|
|
3206
4351
|
ruby_curl_easy_clear_headers_list(rbce);
|
|
3207
4352
|
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
@@ -3216,6 +4361,14 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
|
3216
4361
|
ruby_curl_easy_clear_resolve_list(rbce);
|
|
3217
4362
|
}
|
|
3218
4363
|
|
|
4364
|
+
connect_to = rbce->curl_connect_to;
|
|
4365
|
+
if (connect_to) {
|
|
4366
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4369
|
+
curb_clear_network_allowed_cidr_rules(rbce);
|
|
4370
|
+
curb_clear_network_allowed_hosts(rbce);
|
|
4371
|
+
|
|
3219
4372
|
/* clean up a PUT request's curl options. */
|
|
3220
4373
|
if (!rb_easy_nil("upload")) {
|
|
3221
4374
|
rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
|
|
@@ -3350,6 +4503,23 @@ struct easy_form_perform_args {
|
|
|
3350
4503
|
int form_set_on_curl;
|
|
3351
4504
|
};
|
|
3352
4505
|
|
|
4506
|
+
struct easy_join_args {
|
|
4507
|
+
VALUE args_ary;
|
|
4508
|
+
};
|
|
4509
|
+
|
|
4510
|
+
static VALUE join_easy_arguments_body(VALUE argp) {
|
|
4511
|
+
struct easy_join_args *args = (struct easy_join_args *)argp;
|
|
4512
|
+
return rb_funcall(args->args_ary, idJoin, 1, rbstrAmp);
|
|
4513
|
+
}
|
|
4514
|
+
|
|
4515
|
+
static VALUE join_easy_arguments(ruby_curl_easy *rbce, VALUE args_ary) {
|
|
4516
|
+
struct easy_join_args args = { args_ary };
|
|
4517
|
+
|
|
4518
|
+
ruby_curl_easy_enter_native(rbce);
|
|
4519
|
+
return rb_ensure(join_easy_arguments_body, (VALUE)&args,
|
|
4520
|
+
ruby_curl_easy_leave_native, (VALUE)rbce);
|
|
4521
|
+
}
|
|
4522
|
+
|
|
3353
4523
|
static void append_multipart_form_argument(VALUE arg,
|
|
3354
4524
|
struct curl_httppost **first,
|
|
3355
4525
|
struct curl_httppost **last) {
|
|
@@ -3452,7 +4622,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
3452
4622
|
} else {
|
|
3453
4623
|
VALUE post_body = Qnil;
|
|
3454
4624
|
/* TODO: check for PostField.file and raise error before to_s fails */
|
|
3455
|
-
if ((post_body =
|
|
4625
|
+
if ((post_body = join_easy_arguments(rbce, args_ary)) == Qnil) {
|
|
3456
4626
|
rb_raise(eCurlErrError, "Failed to join arguments");
|
|
3457
4627
|
return Qnil;
|
|
3458
4628
|
} else {
|
|
@@ -3511,7 +4681,7 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
|
3511
4681
|
return ret;
|
|
3512
4682
|
} else {
|
|
3513
4683
|
/* Join arguments into a raw PATCH body */
|
|
3514
|
-
VALUE patch_body =
|
|
4684
|
+
VALUE patch_body = join_easy_arguments(rbce, args_ary);
|
|
3515
4685
|
if (patch_body == Qnil) {
|
|
3516
4686
|
rb_raise(eCurlErrError, "Failed to join arguments");
|
|
3517
4687
|
return Qnil;
|
|
@@ -3570,7 +4740,7 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
3570
4740
|
}
|
|
3571
4741
|
/* Fallback: join all arguments */
|
|
3572
4742
|
else {
|
|
3573
|
-
VALUE post_body =
|
|
4743
|
+
VALUE post_body = join_easy_arguments(rbce, args_ary);
|
|
3574
4744
|
if (post_body != Qnil && rb_type(post_body) == T_STRING &&
|
|
3575
4745
|
RSTRING_LEN(post_body) > 0) {
|
|
3576
4746
|
ruby_curl_easy_put_data_set(self, post_body);
|
|
@@ -3600,6 +4770,47 @@ static VALUE ruby_curl_easy_body_str_get(VALUE self) {
|
|
|
3600
4770
|
CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
|
|
3601
4771
|
}
|
|
3602
4772
|
|
|
4773
|
+
/*
|
|
4774
|
+
* call-seq:
|
|
4775
|
+
* easy.max_body_bytes = bytes_or_nil => bytes_or_nil
|
|
4776
|
+
*
|
|
4777
|
+
* Set an application-level cap for bytes accepted by the body write callback.
|
|
4778
|
+
* +nil+ or 0 clears the cap.
|
|
4779
|
+
*/
|
|
4780
|
+
static VALUE ruby_curl_easy_max_body_bytes_set(VALUE self, VALUE val) {
|
|
4781
|
+
ruby_curl_easy *rbce;
|
|
4782
|
+
long long limit;
|
|
4783
|
+
|
|
4784
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4785
|
+
|
|
4786
|
+
if (NIL_P(val)) {
|
|
4787
|
+
rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
|
|
4788
|
+
return Qnil;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
limit = NUM2LL(val);
|
|
4792
|
+
if (limit < 0) {
|
|
4793
|
+
rb_raise(rb_eArgError, "max_body_bytes must be greater than or equal to zero");
|
|
4794
|
+
}
|
|
4795
|
+
|
|
4796
|
+
if (limit == 0) {
|
|
4797
|
+
rb_hash_delete(rbce->opts, rb_easy_hkey("max_body_bytes"));
|
|
4798
|
+
} else {
|
|
4799
|
+
val = LL2NUM(limit);
|
|
4800
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("max_body_bytes"), val);
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4803
|
+
return val;
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4806
|
+
/*
|
|
4807
|
+
* call-seq:
|
|
4808
|
+
* easy.max_body_bytes => bytes_or_nil
|
|
4809
|
+
*/
|
|
4810
|
+
static VALUE ruby_curl_easy_max_body_bytes_get(VALUE self) {
|
|
4811
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, max_body_bytes);
|
|
4812
|
+
}
|
|
4813
|
+
|
|
3603
4814
|
/*
|
|
3604
4815
|
* call-seq:
|
|
3605
4816
|
* easy.header_str => "response header"
|
|
@@ -4307,12 +5518,28 @@ static VALUE ruby_curl_easy_multi_get(VALUE self) {
|
|
|
4307
5518
|
*/
|
|
4308
5519
|
static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
4309
5520
|
ruby_curl_easy *rbce;
|
|
5521
|
+
VALUE old_multi;
|
|
5522
|
+
ruby_curl_multi *old_rbcm;
|
|
5523
|
+
CURLMcode result;
|
|
4310
5524
|
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4311
5525
|
|
|
4312
5526
|
if (!NIL_P(multi) && rb_obj_is_kind_of(multi, cCurlMulti) != Qtrue) {
|
|
4313
5527
|
rb_raise(rb_eTypeError, "expected Curl::Multi or nil");
|
|
4314
5528
|
}
|
|
4315
5529
|
|
|
5530
|
+
old_multi = rbce->multi;
|
|
5531
|
+
if (old_multi == multi) {
|
|
5532
|
+
return rbce->multi;
|
|
5533
|
+
}
|
|
5534
|
+
|
|
5535
|
+
old_rbcm = ruby_curl_multi_pointer_if_compatible(old_multi);
|
|
5536
|
+
if (old_rbcm) {
|
|
5537
|
+
result = rb_curl_multi_detach_easy(old_rbcm, rbce);
|
|
5538
|
+
if (result != CURLM_OK) {
|
|
5539
|
+
raise_curl_multi_error_exception(result);
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
|
|
4316
5543
|
rbce->multi = multi;
|
|
4317
5544
|
return rbce->multi;
|
|
4318
5545
|
}
|
|
@@ -4355,6 +5582,17 @@ static VALUE ruby_curl_easy_last_error(VALUE self) {
|
|
|
4355
5582
|
* @note Some options - like url or cookie - aren't set directly throught +curl_easy_setopt+, but stored in the Ruby object state.
|
|
4356
5583
|
* @note When +curl_easy_setopt+ is called, return value is not checked here.
|
|
4357
5584
|
*/
|
|
5585
|
+
static long ruby_curl_easy_option_to_long(VALUE value) {
|
|
5586
|
+
if (value == Qtrue) {
|
|
5587
|
+
return 1L;
|
|
5588
|
+
}
|
|
5589
|
+
if (value == Qfalse) {
|
|
5590
|
+
return 0L;
|
|
5591
|
+
}
|
|
5592
|
+
|
|
5593
|
+
return NUM2LONG(rb_funcall(value, rb_intern("to_i"), 0));
|
|
5594
|
+
}
|
|
5595
|
+
|
|
4358
5596
|
static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
4359
5597
|
ruby_curl_easy *rbce;
|
|
4360
5598
|
long option = NUM2LONG(opt);
|
|
@@ -4457,6 +5695,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4457
5695
|
/* Forward request-target directly to libcurl as a string. */
|
|
4458
5696
|
curl_easy_setopt(rbce->curl, CURLOPT_REQUEST_TARGET, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
4459
5697
|
} break;
|
|
5698
|
+
#endif
|
|
5699
|
+
#ifdef HAVE_CURLOPT_DOH_URL
|
|
5700
|
+
case CURLOPT_DOH_URL: {
|
|
5701
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("doh_url"), val);
|
|
5702
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_URL, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5703
|
+
} break;
|
|
4460
5704
|
#endif
|
|
4461
5705
|
case CURLOPT_TCP_NODELAY: {
|
|
4462
5706
|
curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
|
|
@@ -4464,59 +5708,76 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4464
5708
|
/* FTP-specific toggles */
|
|
4465
5709
|
#ifdef HAVE_CURLOPT_DIRLISTONLY
|
|
4466
5710
|
case CURLOPT_DIRLISTONLY: {
|
|
4467
|
-
|
|
4468
|
-
VALUE value;
|
|
4469
|
-
if (type == T_TRUE) {
|
|
4470
|
-
value = rb_int_new(1);
|
|
4471
|
-
} else if (type == T_FALSE) {
|
|
4472
|
-
value = rb_int_new(0);
|
|
4473
|
-
} else {
|
|
4474
|
-
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
4475
|
-
}
|
|
4476
|
-
curl_easy_setopt(rbce->curl, CURLOPT_DIRLISTONLY, NUM2LONG(value));
|
|
5711
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DIRLISTONLY, ruby_curl_easy_option_to_long(val));
|
|
4477
5712
|
} break;
|
|
4478
5713
|
#endif
|
|
5714
|
+
#ifdef HAVE_CURLOPT_FTPPORT
|
|
5715
|
+
case CURLOPT_FTPPORT:
|
|
5716
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTPPORT, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5717
|
+
break;
|
|
5718
|
+
#endif
|
|
5719
|
+
#ifdef HAVE_CURLOPT_APPEND
|
|
5720
|
+
case CURLOPT_APPEND:
|
|
5721
|
+
curl_easy_setopt(rbce->curl, CURLOPT_APPEND, ruby_curl_easy_option_to_long(val));
|
|
5722
|
+
break;
|
|
5723
|
+
#endif
|
|
4479
5724
|
#ifdef HAVE_CURLOPT_FTP_USE_EPSV
|
|
4480
|
-
case CURLOPT_FTP_USE_EPSV:
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
if (type == T_TRUE) {
|
|
4484
|
-
value = rb_int_new(1);
|
|
4485
|
-
} else if (type == T_FALSE) {
|
|
4486
|
-
value = rb_int_new(0);
|
|
4487
|
-
} else {
|
|
4488
|
-
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
4489
|
-
}
|
|
4490
|
-
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPSV, NUM2LONG(value));
|
|
4491
|
-
} break;
|
|
5725
|
+
case CURLOPT_FTP_USE_EPSV:
|
|
5726
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPSV, ruby_curl_easy_option_to_long(val));
|
|
5727
|
+
break;
|
|
4492
5728
|
#endif
|
|
4493
5729
|
#ifdef HAVE_CURLOPT_FTP_USE_EPRT
|
|
4494
|
-
case CURLOPT_FTP_USE_EPRT:
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
5730
|
+
case CURLOPT_FTP_USE_EPRT:
|
|
5731
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPRT, ruby_curl_easy_option_to_long(val));
|
|
5732
|
+
break;
|
|
5733
|
+
#endif
|
|
5734
|
+
#ifdef HAVE_CURLOPT_FTP_USE_PRET
|
|
5735
|
+
case CURLOPT_FTP_USE_PRET:
|
|
5736
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_PRET, ruby_curl_easy_option_to_long(val));
|
|
5737
|
+
break;
|
|
5738
|
+
#endif
|
|
5739
|
+
#ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
|
|
5740
|
+
case CURLOPT_FTP_CREATE_MISSING_DIRS:
|
|
5741
|
+
rb_easy_set("ftp_create_missing_dirs", val);
|
|
5742
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_CREATE_MISSING_DIRS, ruby_curl_easy_option_to_long(val));
|
|
5743
|
+
break;
|
|
5744
|
+
#endif
|
|
5745
|
+
#ifdef HAVE_CURLOPT_FTP_RESPONSE_TIMEOUT
|
|
5746
|
+
case CURLOPT_FTP_RESPONSE_TIMEOUT:
|
|
5747
|
+
rbce->ftp_response_timeout = ruby_curl_easy_option_to_long(val);
|
|
5748
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_RESPONSE_TIMEOUT, rbce->ftp_response_timeout);
|
|
5749
|
+
break;
|
|
5750
|
+
#endif
|
|
5751
|
+
#ifdef HAVE_CURLOPT_FTP_ALTERNATIVE_TO_USER
|
|
5752
|
+
case CURLOPT_FTP_ALTERNATIVE_TO_USER:
|
|
5753
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5754
|
+
break;
|
|
4506
5755
|
#endif
|
|
4507
5756
|
#ifdef HAVE_CURLOPT_FTP_SKIP_PASV_IP
|
|
4508
|
-
case CURLOPT_FTP_SKIP_PASV_IP:
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
5757
|
+
case CURLOPT_FTP_SKIP_PASV_IP:
|
|
5758
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_SKIP_PASV_IP, ruby_curl_easy_option_to_long(val));
|
|
5759
|
+
break;
|
|
5760
|
+
#endif
|
|
5761
|
+
#ifdef HAVE_CURLOPT_FTPSSLAUTH
|
|
5762
|
+
case CURLOPT_FTPSSLAUTH:
|
|
5763
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTPSSLAUTH, ruby_curl_easy_option_to_long(val));
|
|
5764
|
+
break;
|
|
5765
|
+
#endif
|
|
5766
|
+
#ifdef HAVE_CURLOPT_FTP_SSL_CCC
|
|
5767
|
+
case CURLOPT_FTP_SSL_CCC:
|
|
5768
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_SSL_CCC, ruby_curl_easy_option_to_long(val));
|
|
5769
|
+
break;
|
|
5770
|
+
#endif
|
|
5771
|
+
#ifdef HAVE_CURLOPT_FTP_ACCOUNT
|
|
5772
|
+
case CURLOPT_FTP_ACCOUNT:
|
|
5773
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_ACCOUNT, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5774
|
+
break;
|
|
5775
|
+
#endif
|
|
5776
|
+
#ifdef HAVE_CURLOPT_FTP_FILEMETHOD
|
|
5777
|
+
case CURLOPT_FTP_FILEMETHOD:
|
|
5778
|
+
rbce->ftp_filemethod = ruby_curl_easy_option_to_long(val);
|
|
5779
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
|
|
5780
|
+
break;
|
|
4520
5781
|
#endif
|
|
4521
5782
|
case CURLOPT_RANGE: {
|
|
4522
5783
|
curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
|
|
@@ -4531,7 +5792,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4531
5792
|
curl_easy_setopt(rbce->curl, CURLOPT_SSL_CIPHER_LIST, StringValueCStr(val));
|
|
4532
5793
|
} break;
|
|
4533
5794
|
case CURLOPT_FORBID_REUSE: {
|
|
4534
|
-
|
|
5795
|
+
rbce->forbid_reuse = NUM2LONG(val);
|
|
5796
|
+
rbce->forbid_reuse_set = 1;
|
|
5797
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FORBID_REUSE, rbce->forbid_reuse);
|
|
4535
5798
|
} break;
|
|
4536
5799
|
#ifdef HAVE_CURLOPT_GSSAPI_DELEGATION
|
|
4537
5800
|
case CURLOPT_GSSAPI_DELEGATION: {
|
|
@@ -4540,7 +5803,14 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4540
5803
|
#endif
|
|
4541
5804
|
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
4542
5805
|
case CURLOPT_UNIX_SOCKET_PATH: {
|
|
4543
|
-
|
|
5806
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("unix_socket_path"), val);
|
|
5807
|
+
curl_easy_setopt(rbce->curl, CURLOPT_UNIX_SOCKET_PATH, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5808
|
+
} break;
|
|
5809
|
+
#endif
|
|
5810
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
5811
|
+
case CURLOPT_DNS_SERVERS: {
|
|
5812
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("dns_servers"), val);
|
|
5813
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DNS_SERVERS, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
4544
5814
|
} break;
|
|
4545
5815
|
#endif
|
|
4546
5816
|
#ifdef HAVE_CURLOPT_MAX_SEND_SPEED_LARGE
|
|
@@ -4558,6 +5828,11 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4558
5828
|
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
|
|
4559
5829
|
break;
|
|
4560
5830
|
#endif
|
|
5831
|
+
#ifdef HAVE_CURLOPT_MAXFILESIZE_LARGE
|
|
5832
|
+
case CURLOPT_MAXFILESIZE_LARGE:
|
|
5833
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE_LARGE, (curl_off_t)NUM2LL(val));
|
|
5834
|
+
break;
|
|
5835
|
+
#endif
|
|
4561
5836
|
#ifdef HAVE_CURLOPT_TCP_KEEPALIVE
|
|
4562
5837
|
case CURLOPT_TCP_KEEPALIVE:
|
|
4563
5838
|
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
|
|
@@ -4588,6 +5863,16 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4588
5863
|
case CURLOPT_REDIR_PROTOCOLS:
|
|
4589
5864
|
curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
|
|
4590
5865
|
break;
|
|
5866
|
+
#ifdef HAVE_CURLOPT_PROTOCOLS_STR
|
|
5867
|
+
case CURLOPT_PROTOCOLS_STR:
|
|
5868
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROTOCOLS_STR, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5869
|
+
break;
|
|
5870
|
+
#endif
|
|
5871
|
+
#ifdef HAVE_CURLOPT_REDIR_PROTOCOLS_STR
|
|
5872
|
+
case CURLOPT_REDIR_PROTOCOLS_STR:
|
|
5873
|
+
curl_easy_setopt(rbce->curl, CURLOPT_REDIR_PROTOCOLS_STR, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
5874
|
+
break;
|
|
5875
|
+
#endif
|
|
4591
5876
|
#ifdef HAVE_CURLOPT_SSL_SESSIONID_CACHE
|
|
4592
5877
|
case CURLOPT_SSL_SESSIONID_CACHE:
|
|
4593
5878
|
curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
|
|
@@ -4618,6 +5903,21 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4618
5903
|
curl_easy_setopt(rbce->curl, CURLOPT_PROXY_SSL_VERIFYHOST, NUM2LONG(val));
|
|
4619
5904
|
break;
|
|
4620
5905
|
#endif
|
|
5906
|
+
#ifdef HAVE_CURLOPT_DOH_SSL_VERIFYPEER
|
|
5907
|
+
case CURLOPT_DOH_SSL_VERIFYPEER:
|
|
5908
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_SSL_VERIFYPEER, NUM2LONG(val));
|
|
5909
|
+
break;
|
|
5910
|
+
#endif
|
|
5911
|
+
#ifdef HAVE_CURLOPT_DOH_SSL_VERIFYHOST
|
|
5912
|
+
case CURLOPT_DOH_SSL_VERIFYHOST:
|
|
5913
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_SSL_VERIFYHOST, NUM2LONG(val));
|
|
5914
|
+
break;
|
|
5915
|
+
#endif
|
|
5916
|
+
#ifdef HAVE_CURLOPT_DOH_SSL_VERIFYSTATUS
|
|
5917
|
+
case CURLOPT_DOH_SSL_VERIFYSTATUS:
|
|
5918
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DOH_SSL_VERIFYSTATUS, NUM2LONG(val));
|
|
5919
|
+
break;
|
|
5920
|
+
#endif
|
|
4621
5921
|
#ifdef HAVE_CURLOPT_RESOLVE
|
|
4622
5922
|
case CURLOPT_RESOLVE: {
|
|
4623
5923
|
struct curl_slist *list = NULL;
|
|
@@ -4648,6 +5948,34 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4648
5948
|
rb_hash_aset(rbce->opts, rb_easy_hkey("resolve"), val);
|
|
4649
5949
|
curl_easy_setopt(rbce->curl, CURLOPT_RESOLVE, list);
|
|
4650
5950
|
} break;
|
|
5951
|
+
#endif
|
|
5952
|
+
#ifdef HAVE_CURLOPT_CONNECT_TO
|
|
5953
|
+
case CURLOPT_CONNECT_TO: {
|
|
5954
|
+
struct curl_slist *list = NULL;
|
|
5955
|
+
ruby_curl_easy_clear_connect_to_list(rbce);
|
|
5956
|
+
if (NIL_P(val)) {
|
|
5957
|
+
list = NULL;
|
|
5958
|
+
} else if (TYPE(val) == T_ARRAY) {
|
|
5959
|
+
long i, len = RARRAY_LEN(val);
|
|
5960
|
+
for (i = 0; i < len; i++) {
|
|
5961
|
+
VALUE item = rb_ary_entry(val, i);
|
|
5962
|
+
struct curl_slist *new_list = curl_slist_append(list, StringValueCStr(item));
|
|
5963
|
+
if (!new_list) {
|
|
5964
|
+
curl_slist_free_all(list);
|
|
5965
|
+
rb_raise(rb_eNoMemError, "Failed to append to connect-to list");
|
|
5966
|
+
}
|
|
5967
|
+
list = new_list;
|
|
5968
|
+
}
|
|
5969
|
+
} else {
|
|
5970
|
+
list = curl_slist_append(NULL, StringValueCStr(val));
|
|
5971
|
+
if (!list) {
|
|
5972
|
+
rb_raise(rb_eNoMemError, "Failed to create connect-to list");
|
|
5973
|
+
}
|
|
5974
|
+
}
|
|
5975
|
+
rbce->curl_connect_to = list;
|
|
5976
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("connect_to"), val);
|
|
5977
|
+
curl_easy_setopt(rbce->curl, CURLOPT_CONNECT_TO, list);
|
|
5978
|
+
} break;
|
|
4651
5979
|
#endif
|
|
4652
5980
|
default:
|
|
4653
5981
|
rb_raise(rb_eTypeError, "Curb unsupported option");
|
|
@@ -4656,6 +5984,34 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4656
5984
|
return val;
|
|
4657
5985
|
}
|
|
4658
5986
|
|
|
5987
|
+
#ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
|
|
5988
|
+
/*
|
|
5989
|
+
* call-seq:
|
|
5990
|
+
* easy.ftp_create_missing_dirs = boolean_or_mode => boolean_or_mode
|
|
5991
|
+
*
|
|
5992
|
+
* Configure whether libcurl creates missing directories for an FTP or SFTP
|
|
5993
|
+
* transfer. In addition to true and false, this accepts the
|
|
5994
|
+
* Curl::CURLFTP_CREATE_DIR_* mode constants when provided by libcurl.
|
|
5995
|
+
*/
|
|
5996
|
+
static VALUE ruby_curl_easy_ftp_create_missing_dirs_set(VALUE self, VALUE value) {
|
|
5997
|
+
return ruby_curl_easy_set_opt(
|
|
5998
|
+
self,
|
|
5999
|
+
LONG2NUM(CURLOPT_FTP_CREATE_MISSING_DIRS),
|
|
6000
|
+
value
|
|
6001
|
+
);
|
|
6002
|
+
}
|
|
6003
|
+
|
|
6004
|
+
/*
|
|
6005
|
+
* call-seq:
|
|
6006
|
+
* easy.ftp_create_missing_dirs => boolean, number, or nil
|
|
6007
|
+
*
|
|
6008
|
+
* Return the configured missing-directory creation mode.
|
|
6009
|
+
*/
|
|
6010
|
+
static VALUE ruby_curl_easy_ftp_create_missing_dirs_get(VALUE self) {
|
|
6011
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_create_missing_dirs);
|
|
6012
|
+
}
|
|
6013
|
+
#endif
|
|
6014
|
+
|
|
4659
6015
|
/*
|
|
4660
6016
|
* call-seq:
|
|
4661
6017
|
* easy.getinfo(opt) => nil
|
|
@@ -4773,6 +6129,8 @@ static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
|
|
|
4773
6129
|
void init_curb_easy() {
|
|
4774
6130
|
idCall = rb_intern("call");
|
|
4775
6131
|
idJoin = rb_intern("join");
|
|
6132
|
+
idNetworkPolicyNone = rb_intern("none");
|
|
6133
|
+
idNetworkPolicyPublic = rb_intern("public");
|
|
4776
6134
|
|
|
4777
6135
|
rbstrAmp = rb_str_new2("&");
|
|
4778
6136
|
rb_global_variable(&rbstrAmp);
|
|
@@ -4823,6 +6181,17 @@ void init_curb_easy() {
|
|
|
4823
6181
|
rb_define_method(cCurlEasy, "ftp_commands", ruby_curl_easy_ftp_commands_get, 0);
|
|
4824
6182
|
rb_define_method(cCurlEasy, "resolve=", ruby_curl_easy_resolve_set, 1);
|
|
4825
6183
|
rb_define_method(cCurlEasy, "resolve", ruby_curl_easy_resolve_get, 0);
|
|
6184
|
+
rb_define_method(cCurlEasy, "connect_to=", ruby_curl_easy_connect_to_set, 1);
|
|
6185
|
+
rb_define_method(cCurlEasy, "connect_to", ruby_curl_easy_connect_to_get, 0);
|
|
6186
|
+
rb_define_method(cCurlEasy, "doh_url=", ruby_curl_easy_doh_url_set, 1);
|
|
6187
|
+
rb_define_method(cCurlEasy, "doh_url", ruby_curl_easy_doh_url_get, 0);
|
|
6188
|
+
#ifdef HAVE_CURLOPT_DNS_SERVERS
|
|
6189
|
+
rb_define_method(cCurlEasy, "dns_servers", ruby_curl_easy_dns_servers_get, 0);
|
|
6190
|
+
#endif
|
|
6191
|
+
rb_define_method(cCurlEasy, "allowed_cidrs=", ruby_curl_easy_allowed_cidrs_set, 1);
|
|
6192
|
+
rb_define_method(cCurlEasy, "allowed_cidrs", ruby_curl_easy_allowed_cidrs_get, 0);
|
|
6193
|
+
rb_define_method(cCurlEasy, "allowed_hosts=", ruby_curl_easy_allowed_hosts_set, 1);
|
|
6194
|
+
rb_define_method(cCurlEasy, "allowed_hosts", ruby_curl_easy_allowed_hosts_get, 0);
|
|
4826
6195
|
|
|
4827
6196
|
rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
|
|
4828
6197
|
rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
|
|
@@ -4850,6 +6219,10 @@ void init_curb_easy() {
|
|
|
4850
6219
|
rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
|
|
4851
6220
|
rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
|
|
4852
6221
|
rb_define_method(cCurlEasy, "ftp_response_timeout", ruby_curl_easy_ftp_response_timeout_get, 0);
|
|
6222
|
+
#ifdef HAVE_CURLOPT_FTP_CREATE_MISSING_DIRS
|
|
6223
|
+
rb_define_method(cCurlEasy, "ftp_create_missing_dirs=", ruby_curl_easy_ftp_create_missing_dirs_set, 1);
|
|
6224
|
+
rb_define_method(cCurlEasy, "ftp_create_missing_dirs", ruby_curl_easy_ftp_create_missing_dirs_get, 0);
|
|
6225
|
+
#endif
|
|
4853
6226
|
rb_define_method(cCurlEasy, "low_speed_limit=", ruby_curl_easy_low_speed_limit_set, 1);
|
|
4854
6227
|
rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
|
|
4855
6228
|
rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
|
|
@@ -4896,6 +6269,8 @@ void init_curb_easy() {
|
|
|
4896
6269
|
rb_define_method(cCurlEasy, "ignore_content_length?", ruby_curl_easy_ignore_content_length_q, 0);
|
|
4897
6270
|
rb_define_method(cCurlEasy, "resolve_mode", ruby_curl_easy_resolve_mode, 0);
|
|
4898
6271
|
rb_define_method(cCurlEasy, "resolve_mode=", ruby_curl_easy_resolve_mode_set, 1);
|
|
6272
|
+
rb_define_method(cCurlEasy, "network_policy", ruby_curl_easy_network_policy_get, 0);
|
|
6273
|
+
rb_define_method(cCurlEasy, "network_policy=", ruby_curl_easy_network_policy_set, 1);
|
|
4899
6274
|
|
|
4900
6275
|
rb_define_method(cCurlEasy, "on_body", ruby_curl_easy_on_body_set, -1);
|
|
4901
6276
|
rb_define_method(cCurlEasy, "on_header", ruby_curl_easy_on_header_set, -1);
|
|
@@ -4914,6 +6289,8 @@ void init_curb_easy() {
|
|
|
4914
6289
|
|
|
4915
6290
|
/* Post-perform info methods */
|
|
4916
6291
|
rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
|
|
6292
|
+
rb_define_method(cCurlEasy, "max_body_bytes=", ruby_curl_easy_max_body_bytes_set, 1);
|
|
6293
|
+
rb_define_method(cCurlEasy, "max_body_bytes", ruby_curl_easy_max_body_bytes_get, 0);
|
|
4917
6294
|
rb_define_method(cCurlEasy, "header_str", ruby_curl_easy_header_str_get, 0);
|
|
4918
6295
|
|
|
4919
6296
|
rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
|
|
@@ -4964,9 +6341,16 @@ void init_curb_easy() {
|
|
|
4964
6341
|
|
|
4965
6342
|
rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
|
|
4966
6343
|
rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
|
|
6344
|
+
rb_define_private_method(cCurlEasy, "__curb_native_setup!", ruby_curl_easy_setup_self, 0);
|
|
6345
|
+
rb_define_private_method(cCurlEasy, "__curb_allow_proxy=", ruby_curl_easy_allow_proxy_set, 1);
|
|
6346
|
+
rb_define_private_method(cCurlEasy, "__curb_allow_unix_socket=", ruby_curl_easy_allow_unix_socket_set, 1);
|
|
4967
6347
|
rb_define_private_method(cCurlEasy, "_take_callback_error", ruby_curl_easy_take_callback_error, 0);
|
|
4968
6348
|
rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
|
|
4969
6349
|
rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
|
|
6350
|
+
rb_define_method(cCurlEasy, "unsafe_destination_error", ruby_curl_easy_unsafe_destination_error_get, 0);
|
|
6351
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
6352
|
+
rb_define_method(cCurlEasy, "unix_socket_path", ruby_curl_easy_unix_socket_path_get, 0);
|
|
6353
|
+
#endif
|
|
4970
6354
|
|
|
4971
6355
|
rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
|
|
4972
6356
|
rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
|