curb 0.8.4 → 1.3.5
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 +522 -0
- data/Rakefile +79 -26
- data/ext/banned.h +32 -0
- data/ext/curb.c +549 -230
- data/ext/curb.h +19 -10
- data/ext/curb_easy.c +1935 -366
- data/ext/curb_easy.h +16 -0
- data/ext/curb_errors.c +115 -18
- data/ext/curb_errors.h +8 -5
- data/ext/curb_macros.h +33 -21
- data/ext/curb_multi.c +1858 -272
- data/ext/curb_multi.h +10 -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 +353 -35
- data/lib/curb.rb +1 -0
- data/lib/curl/easy.rb +314 -78
- data/lib/curl/multi.rb +134 -28
- data/lib/curl.rb +217 -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 +1 -1
- 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_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 +12 -7
- data/tests/tc_curl_easy.rb +911 -63
- 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 +12 -0
- data/tests/tc_curl_multi.rb +855 -53
- data/tests/tc_curl_native_coverage.rb +145 -0
- data/tests/tc_curl_postfield.rb +207 -30
- data/tests/tc_curl_protocols.rb +37 -0
- data/tests/tc_fiber_scheduler.rb +543 -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 +59 -36
- data/README +0 -194
data/ext/curb_easy.c
CHANGED
|
@@ -12,6 +12,9 @@
|
|
|
12
12
|
|
|
13
13
|
#include <errno.h>
|
|
14
14
|
#include <string.h>
|
|
15
|
+
#ifndef _WIN32
|
|
16
|
+
#include <strings.h>
|
|
17
|
+
#endif
|
|
15
18
|
|
|
16
19
|
extern VALUE mCurl;
|
|
17
20
|
|
|
@@ -25,20 +28,176 @@ static VALUE rbstrAmp;
|
|
|
25
28
|
|
|
26
29
|
VALUE cCurlEasy;
|
|
27
30
|
|
|
31
|
+
/* Internal wrapper type for passing pointers through rb_iterate callbacks.
|
|
32
|
+
* No mark/free needed - these are temporary wrappers that don't own memory. */
|
|
33
|
+
static const rb_data_type_t curl_slist_ptr_type = {
|
|
34
|
+
"curl_slist_ptr_wrapper",
|
|
35
|
+
{ NULL, NULL, NULL },
|
|
36
|
+
NULL, NULL, 0
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// for Ruby 1.8
|
|
40
|
+
#ifndef HAVE_RB_IO_STDIO_FILE
|
|
41
|
+
static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
|
42
|
+
return fptr->f;
|
|
43
|
+
}
|
|
44
|
+
#endif
|
|
45
|
+
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list);
|
|
46
|
+
static size_t proc_data_handler(char *stream, size_t size, size_t nmemb, VALUE proc);
|
|
28
47
|
|
|
29
48
|
/* ================== CURL HANDLER FUNCS ==============*/
|
|
30
49
|
|
|
31
|
-
static VALUE callback_exception(VALUE unused) {
|
|
50
|
+
static VALUE callback_exception(VALUE unused, VALUE exception) {
|
|
32
51
|
return Qfalse;
|
|
33
|
-
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static VALUE callback_exception_store_on_easy(VALUE arg, VALUE exception) {
|
|
55
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
56
|
+
|
|
57
|
+
if (rbce && NIL_P(rbce->callback_error)) {
|
|
58
|
+
rbce->callback_error = exception;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return Qfalse;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
VALUE rb_curl_easy_take_callback_error(ruby_curl_easy *rbce) {
|
|
65
|
+
VALUE exception = Qnil;
|
|
66
|
+
|
|
67
|
+
if (!rbce) {
|
|
68
|
+
return Qnil;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exception = rbce->callback_error;
|
|
72
|
+
rbce->callback_error = Qnil;
|
|
73
|
+
return exception;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static VALUE ruby_curl_easy_take_callback_error(VALUE self) {
|
|
77
|
+
ruby_curl_easy *rbce = NULL;
|
|
78
|
+
|
|
79
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
80
|
+
return rb_curl_easy_take_callback_error(rbce);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static VALUE ensure_clear_easy_callback_active(VALUE arg) {
|
|
84
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)arg;
|
|
85
|
+
if (rbce) {
|
|
86
|
+
rbce->callback_active = 0;
|
|
87
|
+
}
|
|
88
|
+
return Qnil;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
static VALUE with_easy_callback_active(ruby_curl_easy *rbce, VALUE (*func)(VALUE), VALUE arg) {
|
|
92
|
+
rbce->callback_active = 1;
|
|
93
|
+
return rb_ensure(func, arg, ensure_clear_easy_callback_active, (VALUE)rbce);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
struct stream_read_call_args {
|
|
97
|
+
VALUE stream;
|
|
98
|
+
size_t read_bytes;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
static VALUE call_stream_read(VALUE argp) {
|
|
102
|
+
struct stream_read_call_args *args = (struct stream_read_call_args *)argp;
|
|
103
|
+
return rb_funcall(args->stream, rb_intern("read"), 1, ULONG2NUM((unsigned long)args->read_bytes));
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
static VALUE call_stream_to_s(VALUE stream) {
|
|
107
|
+
return rb_funcall(stream, rb_intern("to_s"), 0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static VALUE call_string_value(VALUE str) {
|
|
111
|
+
StringValue(str);
|
|
112
|
+
return str;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
struct stream_seek_call_args {
|
|
116
|
+
VALUE stream;
|
|
117
|
+
curl_off_t offset;
|
|
118
|
+
int origin;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
static VALUE call_stream_seek(VALUE argp) {
|
|
122
|
+
struct stream_seek_call_args *args = (struct stream_seek_call_args *)argp;
|
|
123
|
+
return rb_funcall(args->stream, rb_intern("seek"), 2, LL2NUM(args->offset), INT2NUM(args->origin));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
struct proc_data_call_args {
|
|
127
|
+
char *stream;
|
|
128
|
+
size_t size;
|
|
129
|
+
size_t nmemb;
|
|
130
|
+
VALUE proc;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
static VALUE call_proc_data_handler_wrapped(VALUE argp) {
|
|
134
|
+
struct proc_data_call_args *args = (struct proc_data_call_args *)argp;
|
|
135
|
+
return ULONG2NUM((unsigned long)proc_data_handler(args->stream, args->size, args->nmemb, args->proc));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
struct easy_callback_dispatch_args {
|
|
139
|
+
ruby_curl_easy *rbce;
|
|
140
|
+
VALUE (*func)(VALUE);
|
|
141
|
+
VALUE arg;
|
|
142
|
+
};
|
|
34
143
|
|
|
35
|
-
|
|
36
|
-
|
|
144
|
+
static VALUE call_with_easy_callback_active(VALUE argp) {
|
|
145
|
+
struct easy_callback_dispatch_args *args = (struct easy_callback_dispatch_args *)argp;
|
|
146
|
+
return with_easy_callback_active(args->rbce, args->func, args->arg);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
static VALUE rescue_easy_callback(ruby_curl_easy *rbce, VALUE (*func)(VALUE), VALUE arg) {
|
|
150
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
151
|
+
dispatch_args.rbce = rbce;
|
|
152
|
+
dispatch_args.func = func;
|
|
153
|
+
dispatch_args.arg = arg;
|
|
154
|
+
return rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception_store_on_easy, (VALUE)rbce);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static size_t curl_read_abort_result(void) {
|
|
158
|
+
#ifdef CURL_READFUNC_ABORT
|
|
159
|
+
return CURL_READFUNC_ABORT;
|
|
160
|
+
#else
|
|
161
|
+
return 0;
|
|
162
|
+
#endif
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static int curl_seek_fail_result(void) {
|
|
166
|
+
#ifdef CURL_SEEKFUNC_FAIL
|
|
167
|
+
return CURL_SEEKFUNC_FAIL;
|
|
168
|
+
#else
|
|
169
|
+
return 1;
|
|
170
|
+
#endif
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/* Default body handler appends to easy.body_data buffer */
|
|
174
|
+
static size_t default_body_handler(char *stream,
|
|
37
175
|
size_t size,
|
|
38
176
|
size_t nmemb,
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
177
|
+
void *userdata) {
|
|
178
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)userdata;
|
|
179
|
+
size_t total = size * nmemb;
|
|
180
|
+
VALUE out = rb_easy_get("body_data");
|
|
181
|
+
if (NIL_P(out)) {
|
|
182
|
+
out = rb_easy_set("body_data", rb_str_buf_new(32768));
|
|
183
|
+
}
|
|
184
|
+
rb_str_buf_cat(out, stream, total);
|
|
185
|
+
return total;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* Default header handler appends to easy.header_data buffer */
|
|
189
|
+
static size_t default_header_handler(char *stream,
|
|
190
|
+
size_t size,
|
|
191
|
+
size_t nmemb,
|
|
192
|
+
void *userdata) {
|
|
193
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)userdata;
|
|
194
|
+
size_t total = size * nmemb;
|
|
195
|
+
VALUE out = rb_easy_get("header_data");
|
|
196
|
+
if (NIL_P(out)) {
|
|
197
|
+
out = rb_easy_set("header_data", rb_str_buf_new(16384));
|
|
198
|
+
}
|
|
199
|
+
rb_str_buf_cat(out, stream, total);
|
|
200
|
+
return total;
|
|
42
201
|
}
|
|
43
202
|
|
|
44
203
|
// size_t function( void *ptr, size_t size, size_t nmemb, void *stream);
|
|
@@ -48,14 +207,36 @@ static size_t read_data_handler(void *ptr,
|
|
|
48
207
|
ruby_curl_easy *rbce) {
|
|
49
208
|
VALUE upload = rb_easy_get("upload");
|
|
50
209
|
size_t read_bytes = (size*nmemb);
|
|
51
|
-
VALUE stream
|
|
210
|
+
VALUE stream;
|
|
211
|
+
|
|
212
|
+
if (NIL_P(upload)) {
|
|
213
|
+
return curl_read_abort_result();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
stream = ruby_curl_upload_stream_get(upload);
|
|
52
217
|
|
|
53
218
|
if (rb_respond_to(stream, rb_intern("read"))) {//if (rb_respond_to(stream, rb_intern("to_s"))) {
|
|
54
219
|
/* copy read_bytes from stream into ptr */
|
|
55
|
-
|
|
220
|
+
struct stream_read_call_args args;
|
|
221
|
+
args.stream = stream;
|
|
222
|
+
args.read_bytes = read_bytes;
|
|
223
|
+
VALUE str = rescue_easy_callback(rbce, call_stream_read, (VALUE)&args);
|
|
56
224
|
if( str != Qnil ) {
|
|
57
|
-
|
|
58
|
-
|
|
225
|
+
size_t str_len;
|
|
226
|
+
|
|
227
|
+
str = rescue_easy_callback(rbce, call_string_value, str);
|
|
228
|
+
if (str == Qfalse || str == Qnil) {
|
|
229
|
+
return curl_read_abort_result();
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
str_len = (size_t)RSTRING_LEN(str);
|
|
233
|
+
if (str_len > read_bytes) {
|
|
234
|
+
snprintf(rbce->err_buf, CURL_ERROR_SIZE, "read callback returned more data than requested");
|
|
235
|
+
return curl_read_abort_result();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
memcpy(ptr, RSTRING_PTR(str), str_len);
|
|
239
|
+
return str_len;
|
|
59
240
|
}
|
|
60
241
|
else {
|
|
61
242
|
return 0;
|
|
@@ -67,13 +248,22 @@ static size_t read_data_handler(void *ptr,
|
|
|
67
248
|
size_t len;
|
|
68
249
|
size_t remaining;
|
|
69
250
|
char *str_ptr;
|
|
70
|
-
|
|
71
|
-
str =
|
|
251
|
+
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
252
|
+
str = rescue_easy_callback(rbce, call_stream_to_s, stream);
|
|
253
|
+
str = rescue_easy_callback(rbce, call_string_value, str);
|
|
254
|
+
if (str == Qfalse || str == Qnil) {
|
|
255
|
+
return curl_read_abort_result();
|
|
256
|
+
}
|
|
257
|
+
|
|
72
258
|
len = RSTRING_LEN(str);
|
|
259
|
+
if (rbcu->offset >= len) {
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
73
263
|
remaining = len - rbcu->offset;
|
|
74
264
|
str_ptr = RSTRING_PTR(str);
|
|
75
265
|
|
|
76
|
-
if( remaining
|
|
266
|
+
if( remaining <= read_bytes ) {
|
|
77
267
|
if( remaining > 0 ) {
|
|
78
268
|
memcpy(ptr, str_ptr+rbcu->offset, remaining);
|
|
79
269
|
read_bytes = remaining;
|
|
@@ -81,14 +271,10 @@ static size_t read_data_handler(void *ptr,
|
|
|
81
271
|
}
|
|
82
272
|
return remaining;
|
|
83
273
|
}
|
|
84
|
-
else
|
|
274
|
+
else { // read_bytes < remaining - send what we can fit in the buffer(ptr)
|
|
85
275
|
memcpy(ptr, str_ptr+rbcu->offset, read_bytes);
|
|
86
276
|
rbcu->offset += read_bytes;
|
|
87
277
|
}
|
|
88
|
-
else { // they're equal
|
|
89
|
-
memcpy(ptr, str_ptr+rbcu->offset, --read_bytes);
|
|
90
|
-
rbcu->offset += read_bytes;
|
|
91
|
-
}
|
|
92
278
|
return read_bytes;
|
|
93
279
|
}
|
|
94
280
|
else {
|
|
@@ -96,6 +282,38 @@ static size_t read_data_handler(void *ptr,
|
|
|
96
282
|
}
|
|
97
283
|
}
|
|
98
284
|
|
|
285
|
+
int seek_data_handler(ruby_curl_easy *rbce,
|
|
286
|
+
curl_off_t offset,
|
|
287
|
+
int origin) {
|
|
288
|
+
|
|
289
|
+
VALUE upload = rb_easy_get("upload");
|
|
290
|
+
VALUE stream;
|
|
291
|
+
|
|
292
|
+
if (NIL_P(upload)) {
|
|
293
|
+
return curl_seek_fail_result();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
stream = ruby_curl_upload_stream_get(upload);
|
|
297
|
+
|
|
298
|
+
if (rb_respond_to(stream, rb_intern("seek"))) {
|
|
299
|
+
struct stream_seek_call_args args;
|
|
300
|
+
args.stream = stream;
|
|
301
|
+
args.offset = offset;
|
|
302
|
+
args.origin = origin;
|
|
303
|
+
rescue_easy_callback(rbce, call_stream_seek, (VALUE)&args);
|
|
304
|
+
if (!NIL_P(rbce->callback_error)) {
|
|
305
|
+
return curl_seek_fail_result();
|
|
306
|
+
}
|
|
307
|
+
} else {
|
|
308
|
+
ruby_curl_upload *rbcu;
|
|
309
|
+
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
310
|
+
// This OK because curl only uses SEEK_SET as per the documentation
|
|
311
|
+
rbcu->offset = offset;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return 0;
|
|
315
|
+
}
|
|
316
|
+
|
|
99
317
|
static size_t proc_data_handler(char *stream,
|
|
100
318
|
size_t size,
|
|
101
319
|
size_t nmemb,
|
|
@@ -120,22 +338,40 @@ static size_t proc_data_handler_body(char *stream,
|
|
|
120
338
|
size_t nmemb,
|
|
121
339
|
ruby_curl_easy *rbce)
|
|
122
340
|
{
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
341
|
+
struct proc_data_call_args args;
|
|
342
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
343
|
+
VALUE procret;
|
|
344
|
+
args.stream = stream;
|
|
345
|
+
args.size = size;
|
|
346
|
+
args.nmemb = nmemb;
|
|
347
|
+
args.proc = rb_easy_get("body_proc");
|
|
348
|
+
|
|
349
|
+
dispatch_args.rbce = rbce;
|
|
350
|
+
dispatch_args.func = call_proc_data_handler_wrapped;
|
|
351
|
+
dispatch_args.arg = (VALUE)&args;
|
|
352
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception_store_on_easy, (VALUE)rbce);
|
|
353
|
+
|
|
354
|
+
return ((procret == Qfalse) || (procret == Qnil)) ? 0 : NUM2ULONG(procret);
|
|
128
355
|
}
|
|
129
356
|
static size_t proc_data_handler_header(char *stream,
|
|
130
357
|
size_t size,
|
|
131
358
|
size_t nmemb,
|
|
132
359
|
ruby_curl_easy *rbce)
|
|
133
360
|
{
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
361
|
+
struct proc_data_call_args args;
|
|
362
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
363
|
+
VALUE procret;
|
|
364
|
+
args.stream = stream;
|
|
365
|
+
args.size = size;
|
|
366
|
+
args.nmemb = nmemb;
|
|
367
|
+
args.proc = rb_easy_get("header_proc");
|
|
368
|
+
|
|
369
|
+
dispatch_args.rbce = rbce;
|
|
370
|
+
dispatch_args.func = call_proc_data_handler_wrapped;
|
|
371
|
+
dispatch_args.arg = (VALUE)&args;
|
|
372
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception_store_on_easy, (VALUE)rbce);
|
|
373
|
+
|
|
374
|
+
return ((procret == Qfalse) || (procret == Qnil)) ? 0 : NUM2ULONG(procret);
|
|
139
375
|
}
|
|
140
376
|
|
|
141
377
|
|
|
@@ -147,11 +383,18 @@ static VALUE call_progress_handler(VALUE ary) {
|
|
|
147
383
|
rb_ary_entry(ary, 4)); // rb_float_new(ulnow));
|
|
148
384
|
}
|
|
149
385
|
|
|
150
|
-
|
|
386
|
+
/* CURLOPT_PROGRESSFUNCTION callback (deprecated since 7.32.0) */
|
|
387
|
+
#ifndef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
388
|
+
static int proc_progress_handler(void *clientp,
|
|
151
389
|
double dltotal,
|
|
152
390
|
double dlnow,
|
|
153
391
|
double ultotal,
|
|
154
392
|
double ulnow) {
|
|
393
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
394
|
+
VALUE proc = rb_easy_get("progress_proc");
|
|
395
|
+
if (proc == Qnil) {
|
|
396
|
+
return 0;
|
|
397
|
+
}
|
|
155
398
|
VALUE procret;
|
|
156
399
|
VALUE callargs = rb_ary_new2(5);
|
|
157
400
|
|
|
@@ -161,71 +404,267 @@ static int proc_progress_handler(VALUE proc,
|
|
|
161
404
|
rb_ary_store(callargs, 3, rb_float_new(ultotal));
|
|
162
405
|
rb_ary_store(callargs, 4, rb_float_new(ulnow));
|
|
163
406
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
407
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
408
|
+
dispatch_args.rbce = rbce;
|
|
409
|
+
dispatch_args.func = call_progress_handler;
|
|
410
|
+
dispatch_args.arg = callargs;
|
|
411
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception, Qnil);
|
|
412
|
+
|
|
413
|
+
return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
|
|
414
|
+
}
|
|
415
|
+
#endif
|
|
416
|
+
|
|
417
|
+
/* CURLOPT_XFERINFOFUNCTION callback (since 7.32.0, replaces PROGRESSFUNCTION) */
|
|
418
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
419
|
+
static int proc_xferinfo_handler(void *clientp,
|
|
420
|
+
curl_off_t dltotal,
|
|
421
|
+
curl_off_t dlnow,
|
|
422
|
+
curl_off_t ultotal,
|
|
423
|
+
curl_off_t ulnow) {
|
|
424
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
425
|
+
VALUE proc = rb_easy_get("progress_proc");
|
|
426
|
+
if (proc == Qnil) {
|
|
427
|
+
return 0;
|
|
428
|
+
}
|
|
429
|
+
VALUE procret;
|
|
430
|
+
VALUE callargs = rb_ary_new2(5);
|
|
431
|
+
|
|
432
|
+
rb_ary_store(callargs, 0, proc);
|
|
433
|
+
rb_ary_store(callargs, 1, LL2NUM(dltotal));
|
|
434
|
+
rb_ary_store(callargs, 2, LL2NUM(dlnow));
|
|
435
|
+
rb_ary_store(callargs, 3, LL2NUM(ultotal));
|
|
436
|
+
rb_ary_store(callargs, 4, LL2NUM(ulnow));
|
|
437
|
+
|
|
438
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
439
|
+
dispatch_args.rbce = rbce;
|
|
440
|
+
dispatch_args.func = call_progress_handler;
|
|
441
|
+
dispatch_args.arg = callargs;
|
|
442
|
+
procret = rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception, Qnil);
|
|
170
443
|
|
|
171
444
|
return(((procret == Qfalse) || (procret == Qnil)) ? -1 : 0);
|
|
172
445
|
}
|
|
446
|
+
#endif
|
|
173
447
|
|
|
174
448
|
static VALUE call_debug_handler(VALUE ary) {
|
|
175
449
|
return rb_funcall(rb_ary_entry(ary, 0), idCall, 2,
|
|
176
|
-
rb_ary_entry(ary, 1), //
|
|
450
|
+
rb_ary_entry(ary, 1), // INT2NUM(type),
|
|
177
451
|
rb_ary_entry(ary, 2)); // rb_str_new(data, data_len)
|
|
178
452
|
}
|
|
179
453
|
static int proc_debug_handler(CURL *curl,
|
|
180
454
|
curl_infotype type,
|
|
181
455
|
char *data,
|
|
182
456
|
size_t data_len,
|
|
183
|
-
|
|
457
|
+
void *clientp) {
|
|
458
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)clientp;
|
|
459
|
+
VALUE proc = rb_easy_get("debug_proc");
|
|
460
|
+
if (proc == Qnil) {
|
|
461
|
+
return 0;
|
|
462
|
+
}
|
|
184
463
|
VALUE callargs = rb_ary_new2(3);
|
|
185
464
|
rb_ary_store(callargs, 0, proc);
|
|
186
|
-
rb_ary_store(callargs, 1,
|
|
465
|
+
rb_ary_store(callargs, 1, INT2NUM(type));
|
|
187
466
|
rb_ary_store(callargs, 2, rb_str_new(data, data_len));
|
|
188
|
-
|
|
467
|
+
struct easy_callback_dispatch_args dispatch_args;
|
|
468
|
+
dispatch_args.rbce = rbce;
|
|
469
|
+
dispatch_args.func = call_debug_handler;
|
|
470
|
+
dispatch_args.arg = callargs;
|
|
471
|
+
rb_rescue(call_with_easy_callback_active, (VALUE)&dispatch_args, callback_exception, Qnil);
|
|
189
472
|
/* no way to indicate to libcurl that we should break out given an exception in the on_debug handler...
|
|
190
473
|
* this means exceptions will be swallowed
|
|
191
474
|
*/
|
|
192
|
-
//rb_funcall(proc, idCall, 2,
|
|
475
|
+
//rb_funcall(proc, idCall, 2, INT2NUM(type), rb_str_new(data, data_len));
|
|
193
476
|
return 0;
|
|
194
477
|
}
|
|
195
478
|
|
|
196
|
-
/* ================== MARK/FREE
|
|
197
|
-
void curl_easy_mark(
|
|
198
|
-
|
|
199
|
-
if (
|
|
479
|
+
/* ================== MARK/FREE/SIZE FUNCS ==================*/
|
|
480
|
+
static void curl_easy_mark(void *ptr) {
|
|
481
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)ptr;
|
|
482
|
+
if (rbce) {
|
|
483
|
+
if (!NIL_P(rbce->opts)) { rb_gc_mark(rbce->opts); }
|
|
484
|
+
if (!NIL_P(rbce->multi)) { rb_gc_mark(rbce->multi); }
|
|
485
|
+
if (!NIL_P(rbce->callback_error)) { rb_gc_mark(rbce->callback_error); }
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
static void ruby_curl_easy_clear_headers_list(ruby_curl_easy *rbce) {
|
|
490
|
+
if (!rbce || !rbce->curl_headers) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
if (rbce->curl) {
|
|
494
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HTTPHEADER, NULL);
|
|
495
|
+
}
|
|
496
|
+
curl_slist_free_all(rbce->curl_headers);
|
|
497
|
+
rbce->curl_headers = NULL;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
static void ruby_curl_easy_clear_proxy_headers_list(ruby_curl_easy *rbce) {
|
|
501
|
+
if (!rbce || !rbce->curl_proxy_headers) {
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
#ifdef HAVE_CURLOPT_PROXYHEADER
|
|
505
|
+
if (rbce->curl) {
|
|
506
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROXYHEADER, NULL);
|
|
507
|
+
}
|
|
508
|
+
#endif
|
|
509
|
+
curl_slist_free_all(rbce->curl_proxy_headers);
|
|
510
|
+
rbce->curl_proxy_headers = NULL;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
static void ruby_curl_easy_clear_ftp_commands_list(ruby_curl_easy *rbce) {
|
|
514
|
+
if (!rbce || !rbce->curl_ftp_commands) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
if (rbce->curl) {
|
|
518
|
+
curl_easy_setopt(rbce->curl, CURLOPT_QUOTE, NULL);
|
|
519
|
+
}
|
|
520
|
+
curl_slist_free_all(rbce->curl_ftp_commands);
|
|
521
|
+
rbce->curl_ftp_commands = NULL;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
static void ruby_curl_easy_clear_resolve_list(ruby_curl_easy *rbce) {
|
|
525
|
+
if (!rbce || !rbce->curl_resolve) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
#ifdef HAVE_CURLOPT_RESOLVE
|
|
529
|
+
if (rbce->curl) {
|
|
530
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESOLVE, NULL);
|
|
531
|
+
}
|
|
532
|
+
#endif
|
|
533
|
+
curl_slist_free_all(rbce->curl_resolve);
|
|
534
|
+
rbce->curl_resolve = NULL;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
/* Legacy wrapper for external callers */
|
|
538
|
+
void ruby_curl_easy_mark(ruby_curl_easy *rbce) {
|
|
539
|
+
curl_easy_mark((void *)rbce);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
static ruby_curl_multi *ruby_curl_multi_pointer_if_compatible(VALUE multi_val) {
|
|
543
|
+
if (NIL_P(multi_val) || !RB_TYPE_P(multi_val, T_DATA)) {
|
|
544
|
+
return NULL;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
#if defined(RTYPEDDATA_P) && defined(RTYPEDDATA_TYPE) && defined(RTYPEDDATA_DATA)
|
|
548
|
+
if (!RTYPEDDATA_P(multi_val)) {
|
|
549
|
+
return NULL;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
if (RTYPEDDATA_TYPE(multi_val) != &ruby_curl_multi_data_type) {
|
|
553
|
+
return NULL;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
return (ruby_curl_multi *)RTYPEDDATA_DATA(multi_val);
|
|
557
|
+
#else
|
|
558
|
+
if (!rb_typeddata_is_kind_of(multi_val, &ruby_curl_multi_data_type)) {
|
|
559
|
+
return NULL;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return DATA_PTR(multi_val);
|
|
563
|
+
#endif
|
|
200
564
|
}
|
|
201
565
|
|
|
202
566
|
static void ruby_curl_easy_free(ruby_curl_easy *rbce) {
|
|
203
|
-
if (rbce
|
|
204
|
-
|
|
567
|
+
if (!rbce) {
|
|
568
|
+
return;
|
|
205
569
|
}
|
|
206
570
|
|
|
207
|
-
if (rbce->
|
|
208
|
-
|
|
571
|
+
if (!NIL_P(rbce->multi)) {
|
|
572
|
+
VALUE multi_val = rbce->multi;
|
|
573
|
+
ruby_curl_multi *rbcm = ruby_curl_multi_pointer_if_compatible(multi_val);
|
|
574
|
+
|
|
575
|
+
rbce->multi = Qnil;
|
|
576
|
+
|
|
577
|
+
if (rbcm) {
|
|
578
|
+
/* Best-effort: ensure the handle is detached from the multi to avoid
|
|
579
|
+
* libcurl retaining a dangling pointer to a soon-to-be cleaned-up easy
|
|
580
|
+
* handle. This path runs during GC, so it must not invoke Ruby APIs that
|
|
581
|
+
* can allocate or raise. */
|
|
582
|
+
if (rbcm->handle && rbce->curl) {
|
|
583
|
+
curl_multi_remove_handle(rbcm->handle, rbce->curl);
|
|
584
|
+
}
|
|
585
|
+
rb_curl_multi_forget_easy(rbcm, rbce);
|
|
586
|
+
}
|
|
209
587
|
}
|
|
210
588
|
|
|
589
|
+
ruby_curl_easy_clear_headers_list(rbce);
|
|
590
|
+
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
591
|
+
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
592
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
593
|
+
|
|
211
594
|
if (rbce->curl) {
|
|
595
|
+
/* disable any progress or debug events */
|
|
596
|
+
curl_easy_setopt(rbce->curl, CURLOPT_WRITEFUNCTION, NULL);
|
|
597
|
+
curl_easy_setopt(rbce->curl, CURLOPT_WRITEDATA, NULL);
|
|
598
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HEADERFUNCTION, NULL);
|
|
599
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HEADERDATA, NULL);
|
|
600
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DEBUGFUNCTION, NULL);
|
|
601
|
+
curl_easy_setopt(rbce->curl, CURLOPT_DEBUGDATA, NULL);
|
|
602
|
+
curl_easy_setopt(rbce->curl, CURLOPT_VERBOSE, 0);
|
|
603
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
604
|
+
curl_easy_setopt(rbce->curl, CURLOPT_XFERINFOFUNCTION, NULL);
|
|
605
|
+
#else
|
|
606
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROGRESSFUNCTION, NULL);
|
|
607
|
+
#endif
|
|
608
|
+
curl_easy_setopt(rbce->curl, CURLOPT_NOPROGRESS, 1);
|
|
212
609
|
curl_easy_cleanup(rbce->curl);
|
|
610
|
+
rbce->curl = NULL;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
rbce->self = Qnil;
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
/* TypedData-compatible free function */
|
|
617
|
+
static void curl_easy_free(void *ptr) {
|
|
618
|
+
ruby_curl_easy *rbce = (ruby_curl_easy *)ptr;
|
|
619
|
+
if (rbce) {
|
|
620
|
+
ruby_curl_easy_free(rbce);
|
|
621
|
+
free(rbce);
|
|
213
622
|
}
|
|
214
623
|
}
|
|
215
624
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
625
|
+
/* Legacy wrapper for external callers (e.g., curb_multi) */
|
|
626
|
+
void ruby_curl_easy_free_wrapper(ruby_curl_easy *rbce) {
|
|
627
|
+
curl_easy_free((void *)rbce);
|
|
219
628
|
}
|
|
220
629
|
|
|
630
|
+
static size_t curl_easy_memsize(const void *ptr) {
|
|
631
|
+
const ruby_curl_easy *rbce = (const ruby_curl_easy *)ptr;
|
|
632
|
+
size_t size = sizeof(ruby_curl_easy);
|
|
633
|
+
/* Note: We don't count curl_slist or CURL handle memory as they're
|
|
634
|
+
* managed by libcurl and would require complex introspection */
|
|
635
|
+
(void)rbce; /* silence unused warning */
|
|
636
|
+
return size;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
const rb_data_type_t ruby_curl_easy_data_type = {
|
|
640
|
+
"Curl::Easy",
|
|
641
|
+
{
|
|
642
|
+
curl_easy_mark,
|
|
643
|
+
curl_easy_free,
|
|
644
|
+
curl_easy_memsize,
|
|
645
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
646
|
+
NULL, /* compact - not needed */
|
|
647
|
+
#endif
|
|
648
|
+
},
|
|
649
|
+
#ifdef RUBY_TYPED_FREE_IMMEDIATELY
|
|
650
|
+
NULL, NULL, /* parent, data */
|
|
651
|
+
RUBY_TYPED_FREE_IMMEDIATELY
|
|
652
|
+
#endif
|
|
653
|
+
};
|
|
654
|
+
|
|
221
655
|
|
|
222
656
|
/* ================= ALLOC METHODS ====================*/
|
|
223
657
|
|
|
224
658
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
225
659
|
rbce->opts = rb_hash_new();
|
|
226
660
|
|
|
661
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
662
|
+
|
|
663
|
+
rbce->self = Qnil;
|
|
227
664
|
rbce->curl_headers = NULL;
|
|
665
|
+
rbce->curl_proxy_headers = NULL;
|
|
228
666
|
rbce->curl_ftp_commands = NULL;
|
|
667
|
+
rbce->curl_resolve = NULL;
|
|
229
668
|
|
|
230
669
|
/* various-typed opts */
|
|
231
670
|
rbce->local_port = 0;
|
|
@@ -236,14 +675,19 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
236
675
|
rbce->proxy_auth_types = 0;
|
|
237
676
|
rbce->max_redirs = -1;
|
|
238
677
|
rbce->timeout = 0;
|
|
678
|
+
rbce->timeout_ms = 0;
|
|
239
679
|
rbce->connect_timeout = 0;
|
|
680
|
+
rbce->connect_timeout_ms = 0;
|
|
240
681
|
rbce->dns_cache_timeout = 60;
|
|
241
682
|
rbce->ftp_response_timeout = 0;
|
|
242
683
|
rbce->low_speed_limit = 0;
|
|
243
684
|
rbce->low_speed_time = 0;
|
|
685
|
+
rbce->max_send_speed_large = 0;
|
|
686
|
+
rbce->max_recv_speed_large = 0;
|
|
244
687
|
rbce->ssl_version = -1;
|
|
245
688
|
rbce->use_ssl = -1;
|
|
246
689
|
rbce->ftp_filemethod = -1;
|
|
690
|
+
rbce->http_version = CURL_HTTP_VERSION_NONE;
|
|
247
691
|
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
248
692
|
|
|
249
693
|
/* bool opts */
|
|
@@ -258,29 +702,47 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
|
258
702
|
rbce->verbose = 0;
|
|
259
703
|
rbce->multipart_form_post = 0;
|
|
260
704
|
rbce->enable_cookies = 0;
|
|
705
|
+
rbce->cookielist_engine_enabled = 0;
|
|
261
706
|
rbce->ignore_content_length = 0;
|
|
262
707
|
rbce->callback_active = 0;
|
|
708
|
+
rbce->callback_error = Qnil;
|
|
709
|
+
rbce->last_result = 0;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
/*
|
|
713
|
+
* Allocate space for a Curl::Easy instance.
|
|
714
|
+
*/
|
|
715
|
+
static VALUE ruby_curl_easy_allocate(VALUE klass) {
|
|
716
|
+
ruby_curl_easy *rbce;
|
|
717
|
+
rbce = ALLOC(ruby_curl_easy);
|
|
718
|
+
if (!rbce) {
|
|
719
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for Curl::Easy");
|
|
720
|
+
}
|
|
721
|
+
rbce->curl = NULL;
|
|
722
|
+
rbce->opts = Qnil;
|
|
723
|
+
rbce->multi = Qnil;
|
|
724
|
+
ruby_curl_easy_zero(rbce);
|
|
725
|
+
return TypedData_Wrap_Struct(klass, &ruby_curl_easy_data_type, rbce);
|
|
263
726
|
}
|
|
264
727
|
|
|
265
728
|
/*
|
|
266
729
|
* call-seq:
|
|
267
|
-
* Curl::Easy.new =>
|
|
268
|
-
* Curl::Easy.new(url = nil) =>
|
|
269
|
-
* Curl::Easy.new(url = nil) { |self| ... } =>
|
|
730
|
+
* Curl::Easy.new => #<Curl::Easy...>
|
|
731
|
+
* Curl::Easy.new(url = nil) => #<Curl::Easy...>
|
|
732
|
+
* Curl::Easy.new(url = nil) { |self| ... } => #<Curl::Easy...>
|
|
270
733
|
*
|
|
271
|
-
*
|
|
734
|
+
* Initialize a new Curl::Easy instance, optionally supplying the URL.
|
|
272
735
|
* The block form allows further configuration to be supplied before
|
|
273
736
|
* the instance is returned.
|
|
274
737
|
*/
|
|
275
|
-
static VALUE
|
|
738
|
+
static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
276
739
|
CURLcode ecode;
|
|
277
740
|
VALUE url, blk;
|
|
278
|
-
VALUE new_curl;
|
|
279
741
|
ruby_curl_easy *rbce;
|
|
280
742
|
|
|
281
743
|
rb_scan_args(argc, argv, "01&", &url, &blk);
|
|
282
744
|
|
|
283
|
-
|
|
745
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
284
746
|
|
|
285
747
|
/* handler */
|
|
286
748
|
rbce->curl = curl_easy_init();
|
|
@@ -288,32 +750,67 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
|
288
750
|
rb_raise(eCurlErrFailedInit, "Failed to initialize easy handle");
|
|
289
751
|
}
|
|
290
752
|
|
|
291
|
-
new_curl = Data_Wrap_Struct(klass, curl_easy_mark, curl_easy_free, rbce);
|
|
292
|
-
|
|
293
753
|
rbce->multi = Qnil;
|
|
294
754
|
rbce->opts = Qnil;
|
|
295
755
|
|
|
296
756
|
ruby_curl_easy_zero(rbce);
|
|
757
|
+
rbce->self = self;
|
|
758
|
+
|
|
759
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
|
297
760
|
|
|
298
761
|
rb_easy_set("url", url);
|
|
299
762
|
|
|
300
|
-
/* set the
|
|
301
|
-
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)
|
|
763
|
+
/* set the pointer to the curl handle */
|
|
764
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
302
765
|
if (ecode != CURLE_OK) {
|
|
303
766
|
raise_curl_easy_error_exception(ecode);
|
|
304
767
|
}
|
|
305
768
|
|
|
306
769
|
if (blk != Qnil) {
|
|
307
|
-
rb_funcall(blk, idCall, 1,
|
|
770
|
+
rb_funcall(blk, idCall, 1, self);
|
|
308
771
|
}
|
|
309
772
|
|
|
310
|
-
return
|
|
773
|
+
return self;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/* Helper to duplicate a curl_slist */
|
|
777
|
+
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list) {
|
|
778
|
+
struct curl_slist *dup = NULL;
|
|
779
|
+
struct curl_slist *tmp;
|
|
780
|
+
struct curl_slist *new_list;
|
|
781
|
+
for (tmp = list; tmp; tmp = tmp->next) {
|
|
782
|
+
new_list = curl_slist_append(dup, tmp->data);
|
|
783
|
+
if (!new_list) {
|
|
784
|
+
if (dup) { curl_slist_free_all(dup); }
|
|
785
|
+
rb_raise(rb_eNoMemError, "Failed to duplicate curl_slist");
|
|
786
|
+
}
|
|
787
|
+
dup = new_list;
|
|
788
|
+
}
|
|
789
|
+
return dup;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
static VALUE duplicate_upload(VALUE upload) {
|
|
793
|
+
ruby_curl_upload *rbcu, *newrbcu;
|
|
794
|
+
VALUE new_upload;
|
|
795
|
+
|
|
796
|
+
if (NIL_P(upload)) {
|
|
797
|
+
return Qnil;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
801
|
+
|
|
802
|
+
new_upload = ruby_curl_upload_new(cCurlUpload);
|
|
803
|
+
TypedData_Get_Struct(new_upload, ruby_curl_upload, &ruby_curl_upload_data_type, newrbcu);
|
|
804
|
+
newrbcu->stream = rbcu->stream;
|
|
805
|
+
newrbcu->offset = rbcu->offset;
|
|
806
|
+
|
|
807
|
+
return new_upload;
|
|
311
808
|
}
|
|
312
809
|
|
|
313
810
|
/*
|
|
314
811
|
* call-seq:
|
|
315
|
-
* easy.clone =>
|
|
316
|
-
* easy.dup =>
|
|
812
|
+
* easy.clone => <easy clone>
|
|
813
|
+
* easy.dup => <easy clone>
|
|
317
814
|
*
|
|
318
815
|
* Clone this Curl::Easy instance, creating a new instance.
|
|
319
816
|
* This method duplicates the underlying CURL* handle.
|
|
@@ -321,15 +818,57 @@ static VALUE ruby_curl_easy_new(int argc, VALUE *argv, VALUE klass) {
|
|
|
321
818
|
static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
322
819
|
ruby_curl_easy *rbce, *newrbce;
|
|
323
820
|
|
|
324
|
-
|
|
821
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
325
822
|
|
|
326
823
|
newrbce = ALLOC(ruby_curl_easy);
|
|
824
|
+
if (!newrbce) {
|
|
825
|
+
rb_raise(rb_eNoMemError, "Failed to allocate memory for Curl::Easy clone");
|
|
826
|
+
}
|
|
827
|
+
/* shallow copy */
|
|
327
828
|
memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
|
|
829
|
+
|
|
830
|
+
/* now deep copy */
|
|
328
831
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
|
329
|
-
newrbce->
|
|
330
|
-
|
|
832
|
+
if (!newrbce->curl) {
|
|
833
|
+
free(newrbce);
|
|
834
|
+
rb_raise(rb_eNoMemError, "Failed to duplicate Curl::Easy handle");
|
|
835
|
+
}
|
|
836
|
+
newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
|
|
837
|
+
newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
|
|
838
|
+
newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
|
|
839
|
+
newrbce->curl_resolve = (rbce->curl_resolve) ? duplicate_curl_slist(rbce->curl_resolve) : NULL;
|
|
331
840
|
|
|
332
|
-
|
|
841
|
+
/* A cloned easy should not retain ownership reference to the original multi. */
|
|
842
|
+
newrbce->multi = Qnil;
|
|
843
|
+
newrbce->callback_error = Qnil;
|
|
844
|
+
|
|
845
|
+
if (rbce->opts != Qnil) {
|
|
846
|
+
newrbce->opts = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/* Set the error buffer on the new curl handle using the new err_buf */
|
|
850
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_ERRORBUFFER, newrbce->err_buf);
|
|
851
|
+
|
|
852
|
+
if (newrbce->opts != Qnil) {
|
|
853
|
+
VALUE upload = rb_hash_aref(newrbce->opts, rb_easy_hkey("upload"));
|
|
854
|
+
if (!NIL_P(upload)) {
|
|
855
|
+
rb_hash_aset(newrbce->opts, rb_easy_hkey("upload"), duplicate_upload(upload));
|
|
856
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
857
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_READDATA, newrbce);
|
|
858
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
859
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
|
|
860
|
+
#endif
|
|
861
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
862
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_SEEKDATA, newrbce);
|
|
863
|
+
#endif
|
|
864
|
+
}
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
VALUE clone = TypedData_Wrap_Struct(cCurlEasy, &ruby_curl_easy_data_type, newrbce);
|
|
868
|
+
newrbce->self = clone;
|
|
869
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_PRIVATE, (void*)newrbce);
|
|
870
|
+
|
|
871
|
+
return clone;
|
|
333
872
|
}
|
|
334
873
|
|
|
335
874
|
/*
|
|
@@ -337,14 +876,14 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
337
876
|
* easy.close => nil
|
|
338
877
|
*
|
|
339
878
|
* Close the Curl::Easy instance. Any open connections are closed
|
|
340
|
-
* The easy handle is reinitialized. If a previous multi handle was
|
|
879
|
+
* The easy handle is reinitialized. If a previous multi handle was
|
|
341
880
|
* open it is set to nil and will be cleared after a GC.
|
|
342
881
|
*/
|
|
343
882
|
static VALUE ruby_curl_easy_close(VALUE self) {
|
|
344
883
|
CURLcode ecode;
|
|
345
884
|
ruby_curl_easy *rbce;
|
|
346
885
|
|
|
347
|
-
|
|
886
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
348
887
|
|
|
349
888
|
if (rbce->callback_active) {
|
|
350
889
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
@@ -361,9 +900,12 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
361
900
|
rbce->multi = Qnil;
|
|
362
901
|
|
|
363
902
|
ruby_curl_easy_zero(rbce);
|
|
903
|
+
rbce->self = self;
|
|
904
|
+
|
|
905
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, rbce->err_buf);
|
|
364
906
|
|
|
365
907
|
/* give the new curl handle a reference back to the ruby object */
|
|
366
|
-
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)
|
|
908
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
367
909
|
if (ecode != CURLE_OK) {
|
|
368
910
|
raise_curl_easy_error_exception(ecode);
|
|
369
911
|
}
|
|
@@ -387,7 +929,7 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
|
387
929
|
CURLcode ecode;
|
|
388
930
|
ruby_curl_easy *rbce;
|
|
389
931
|
VALUE opts_dup;
|
|
390
|
-
|
|
932
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
391
933
|
|
|
392
934
|
if (rbce->callback_active) {
|
|
393
935
|
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
|
@@ -395,21 +937,19 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
|
395
937
|
|
|
396
938
|
opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
|
397
939
|
|
|
940
|
+
ruby_curl_easy_cleanup(self, rbce);
|
|
398
941
|
curl_easy_reset(rbce->curl);
|
|
399
942
|
ruby_curl_easy_zero(rbce);
|
|
943
|
+
rbce->self = self;
|
|
400
944
|
|
|
401
|
-
|
|
402
|
-
|
|
945
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, &rbce->err_buf);
|
|
946
|
+
|
|
947
|
+
/* reset clobbers the private setting, so reset it to self */
|
|
948
|
+
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
403
949
|
if (ecode != CURLE_OK) {
|
|
404
950
|
raise_curl_easy_error_exception(ecode);
|
|
405
951
|
}
|
|
406
952
|
|
|
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
953
|
return opts_dup;
|
|
414
954
|
}
|
|
415
955
|
|
|
@@ -462,6 +1002,10 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
|
|
|
462
1002
|
CURB_OBJECT_HSETTER(ruby_curl_easy, headers);
|
|
463
1003
|
}
|
|
464
1004
|
|
|
1005
|
+
static VALUE ruby_curl_easy_proxy_headers_set(VALUE self, VALUE proxy_headers) {
|
|
1006
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_headers);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
465
1009
|
/*
|
|
466
1010
|
* call-seq:
|
|
467
1011
|
* easy.headers => Hash, Array or Str
|
|
@@ -471,12 +1015,47 @@ static VALUE ruby_curl_easy_headers_set(VALUE self, VALUE headers) {
|
|
|
471
1015
|
static VALUE ruby_curl_easy_headers_get(VALUE self) {
|
|
472
1016
|
ruby_curl_easy *rbce;
|
|
473
1017
|
VALUE headers;
|
|
474
|
-
|
|
475
|
-
headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
|
|
1018
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1019
|
+
headers = rb_easy_get("headers");//rb_hash_aref(rbce->opts, rb_intern("headers"));
|
|
476
1020
|
if (headers == Qnil) { headers = rb_easy_set("headers", rb_hash_new()); }
|
|
477
1021
|
return headers;
|
|
478
1022
|
}
|
|
479
1023
|
|
|
1024
|
+
/*
|
|
1025
|
+
* call-seq:
|
|
1026
|
+
* easy.proxy_headers = "Header: val" => "Header: val"
|
|
1027
|
+
* easy.proxy_headers = {"Header" => "val" ..., "Header" => "val"} => {"Header: val", ...}
|
|
1028
|
+
* easy.proxy_headers = ["Header: val" ..., "Header: val"] => ["Header: val", ...]
|
|
1029
|
+
*
|
|
1030
|
+
*
|
|
1031
|
+
* For example to set a standard or custom header:
|
|
1032
|
+
*
|
|
1033
|
+
* easy.proxy_headers["MyHeader"] = "myval"
|
|
1034
|
+
*
|
|
1035
|
+
* To remove a standard header (this is useful when removing libcurls default
|
|
1036
|
+
* 'Expect: 100-Continue' header when using HTTP form posts):
|
|
1037
|
+
*
|
|
1038
|
+
* easy.proxy_headers["Expect"] = ''
|
|
1039
|
+
*
|
|
1040
|
+
* Anything passed to libcurl as a header will be converted to a string during
|
|
1041
|
+
* the perform step.
|
|
1042
|
+
*/
|
|
1043
|
+
|
|
1044
|
+
/*
|
|
1045
|
+
* call-seq:
|
|
1046
|
+
* easy.proxy_headers => Hash, Array or Str
|
|
1047
|
+
*
|
|
1048
|
+
* Obtain the custom HTTP proxy_headers for following requests.
|
|
1049
|
+
*/
|
|
1050
|
+
static VALUE ruby_curl_easy_proxy_headers_get(VALUE self) {
|
|
1051
|
+
ruby_curl_easy *rbce;
|
|
1052
|
+
VALUE proxy_headers;
|
|
1053
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1054
|
+
proxy_headers = rb_easy_get("proxy_headers");//rb_hash_aref(rbce->opts, rb_intern("proxy_headers"));
|
|
1055
|
+
if (proxy_headers == Qnil) { proxy_headers = rb_easy_set("proxy_headers", rb_hash_new()); }
|
|
1056
|
+
return proxy_headers;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
480
1059
|
/*
|
|
481
1060
|
* call-seq:
|
|
482
1061
|
* easy.interface => string
|
|
@@ -515,7 +1094,16 @@ static VALUE ruby_curl_easy_proxypwd_get(VALUE self) {
|
|
|
515
1094
|
* call-seq:
|
|
516
1095
|
* easy.cookies => "name1=content1; name2=content2;"
|
|
517
1096
|
*
|
|
518
|
-
* Obtain the
|
|
1097
|
+
* Obtain the manually set Cookie header string for this Curl::Easy instance.
|
|
1098
|
+
*
|
|
1099
|
+
* Notes:
|
|
1100
|
+
* - This corresponds to libcurl's CURLOPT_COOKIE and only affects the outgoing
|
|
1101
|
+
* Cookie request header. It does NOT modify the internal libcurl cookie engine
|
|
1102
|
+
* that stores cookies received via Set-Cookie.
|
|
1103
|
+
* - To inspect or modify cookies stored in the cookie engine, use
|
|
1104
|
+
* +easy.cookielist+ (getter) and +easy.cookielist=+ or +easy.set(:cookielist, ...)+ (setter).
|
|
1105
|
+
* - To clear a previously set manual Cookie header, assign an empty string.
|
|
1106
|
+
* Assigning +nil+ currently has no effect.
|
|
519
1107
|
*/
|
|
520
1108
|
static VALUE ruby_curl_easy_cookies_get(VALUE self) {
|
|
521
1109
|
CURB_OBJECT_HGETTER(ruby_curl_easy, cookies);
|
|
@@ -525,7 +1113,8 @@ static VALUE ruby_curl_easy_cookies_get(VALUE self) {
|
|
|
525
1113
|
* call-seq:
|
|
526
1114
|
* easy.cookiefile => string
|
|
527
1115
|
*
|
|
528
|
-
* Obtain the cookiefile
|
|
1116
|
+
* Obtain the cookiefile path for this Curl::Easy instance (used to load cookies when the
|
|
1117
|
+
* cookie engine is enabled).
|
|
529
1118
|
*/
|
|
530
1119
|
static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
|
|
531
1120
|
CURB_OBJECT_HGETTER(ruby_curl_easy, cookiefile);
|
|
@@ -535,7 +1124,8 @@ static VALUE ruby_curl_easy_cookiefile_get(VALUE self) {
|
|
|
535
1124
|
* call-seq:
|
|
536
1125
|
* easy.cookiejar => string
|
|
537
1126
|
*
|
|
538
|
-
* Obtain the cookiejar
|
|
1127
|
+
* Obtain the cookiejar path for this Curl::Easy instance (used to persist cookies when the
|
|
1128
|
+
* cookie engine is enabled).
|
|
539
1129
|
*/
|
|
540
1130
|
static VALUE ruby_curl_easy_cookiejar_get(VALUE self) {
|
|
541
1131
|
CURB_OBJECT_HGETTER(ruby_curl_easy, cookiejar);
|
|
@@ -684,57 +1274,81 @@ static VALUE ruby_curl_easy_useragent_get(VALUE self) {
|
|
|
684
1274
|
/*
|
|
685
1275
|
* call-seq:
|
|
686
1276
|
* easy.post_body = "some=form%20data&to=send" => string or nil
|
|
687
|
-
*
|
|
1277
|
+
*
|
|
688
1278
|
* Sets the POST body of this Curl::Easy instance. This is expected to be
|
|
689
1279
|
* URL encoded; no additional processing or encoding is done on the string.
|
|
690
1280
|
* The content-type header will be set to application/x-www-form-urlencoded.
|
|
691
|
-
*
|
|
1281
|
+
*
|
|
692
1282
|
* This is handy if you want to perform a POST against a Curl::Multi instance.
|
|
693
1283
|
*/
|
|
694
|
-
static VALUE
|
|
1284
|
+
static VALUE ruby_curl_easy_post_body_set_with_mode(VALUE self, VALUE post_body, int force_http_get_on_nil) {
|
|
695
1285
|
ruby_curl_easy *rbce;
|
|
696
1286
|
CURL *curl;
|
|
697
|
-
|
|
1287
|
+
|
|
1288
|
+
VALUE body_str;
|
|
1289
|
+
VALUE retained_body_str;
|
|
698
1290
|
char *data;
|
|
699
1291
|
long len;
|
|
700
1292
|
|
|
701
|
-
|
|
702
|
-
|
|
1293
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1294
|
+
|
|
703
1295
|
curl = rbce->curl;
|
|
704
|
-
|
|
1296
|
+
|
|
705
1297
|
if ( post_body == Qnil ) {
|
|
706
1298
|
rb_easy_del("postdata_buffer");
|
|
707
|
-
curl_easy_setopt(curl,
|
|
708
|
-
|
|
709
|
-
|
|
1299
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
|
1300
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
|
|
1301
|
+
if (force_http_get_on_nil) {
|
|
1302
|
+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
} else {
|
|
710
1306
|
if (rb_type(post_body) == T_STRING) {
|
|
711
|
-
|
|
712
|
-
len = RSTRING_LEN(post_body);
|
|
1307
|
+
body_str = post_body;
|
|
713
1308
|
}
|
|
714
1309
|
else if (rb_respond_to(post_body, rb_intern("to_s"))) {
|
|
715
|
-
|
|
716
|
-
data = StringValuePtr(str_body);
|
|
717
|
-
len = RSTRING_LEN(post_body);
|
|
1310
|
+
body_str = rb_funcall(post_body, rb_intern("to_s"), 0);
|
|
718
1311
|
}
|
|
719
1312
|
else {
|
|
720
1313
|
rb_raise(rb_eRuntimeError, "post data must respond_to .to_s");
|
|
721
1314
|
}
|
|
722
|
-
|
|
723
|
-
|
|
1315
|
+
|
|
1316
|
+
StringValue(body_str);
|
|
1317
|
+
|
|
1318
|
+
// Store the string, since it has to hang around for the duration of the
|
|
724
1319
|
// request. See CURLOPT_POSTFIELDS in the libcurl docs.
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
1320
|
+
#ifdef HAVE_CURLOPT_COPYPOSTFIELDS
|
|
1321
|
+
/*
|
|
1322
|
+
* libcurl copies the bytes immediately for COPYPOSTFIELDS, so retain a
|
|
1323
|
+
* matching Ruby snapshot for post_body instead of the caller's mutable
|
|
1324
|
+
* source string.
|
|
1325
|
+
*/
|
|
1326
|
+
retained_body_str = rb_str_dup(body_str);
|
|
1327
|
+
#else
|
|
1328
|
+
retained_body_str = body_str;
|
|
1329
|
+
#endif
|
|
1330
|
+
data = StringValuePtr(retained_body_str);
|
|
1331
|
+
len = RSTRING_LEN(retained_body_str);
|
|
1332
|
+
rb_easy_set("postdata_buffer", retained_body_str);
|
|
1333
|
+
|
|
728
1334
|
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
|
729
|
-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
|
|
730
1335
|
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
|
|
731
|
-
|
|
1336
|
+
#ifdef HAVE_CURLOPT_COPYPOSTFIELDS
|
|
1337
|
+
curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, data);
|
|
1338
|
+
#else
|
|
1339
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
|
|
1340
|
+
#endif
|
|
1341
|
+
|
|
732
1342
|
return post_body;
|
|
733
1343
|
}
|
|
734
|
-
|
|
1344
|
+
|
|
735
1345
|
return Qnil;
|
|
736
1346
|
}
|
|
737
1347
|
|
|
1348
|
+
static VALUE ruby_curl_easy_post_body_set(VALUE self, VALUE post_body) {
|
|
1349
|
+
return ruby_curl_easy_post_body_set_with_mode(self, post_body, 1);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
738
1352
|
/*
|
|
739
1353
|
* call-seq:
|
|
740
1354
|
* easy.post_body => string or nil
|
|
@@ -748,7 +1362,7 @@ static VALUE ruby_curl_easy_post_body_get(VALUE self) {
|
|
|
748
1362
|
/*
|
|
749
1363
|
* call-seq:
|
|
750
1364
|
* easy.put_data = data => ""
|
|
751
|
-
*
|
|
1365
|
+
*
|
|
752
1366
|
* Points this Curl::Easy instance to data to be uploaded via PUT. This
|
|
753
1367
|
* sets the request to a PUT type request - useful if you want to PUT via
|
|
754
1368
|
* a multi handle.
|
|
@@ -757,26 +1371,15 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
757
1371
|
ruby_curl_easy *rbce;
|
|
758
1372
|
CURL *curl;
|
|
759
1373
|
VALUE upload;
|
|
1374
|
+
VALUE upload_stream = data;
|
|
760
1375
|
VALUE headers;
|
|
1376
|
+
VALUE infile_size = Qnil;
|
|
761
1377
|
|
|
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);
|
|
1378
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
776
1379
|
|
|
777
|
-
/*
|
|
778
|
-
*
|
|
779
|
-
*
|
|
1380
|
+
/*
|
|
1381
|
+
* Validate and prepare Ruby-visible state before mutating the CURL handle.
|
|
1382
|
+
* Several branches below can raise (header type, stat, size, to_s).
|
|
780
1383
|
*/
|
|
781
1384
|
if (!rb_easy_nil("headers")) {
|
|
782
1385
|
if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_STRING)) {
|
|
@@ -784,43 +1387,80 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
784
1387
|
}
|
|
785
1388
|
}
|
|
786
1389
|
|
|
787
|
-
|
|
788
|
-
|
|
1390
|
+
if (!NIL_P(data) && !rb_respond_to(data, rb_intern("read"))) {
|
|
1391
|
+
if (rb_respond_to(data, rb_intern("to_s"))) {
|
|
1392
|
+
upload_stream = rb_obj_as_string(data);
|
|
1393
|
+
} else {
|
|
1394
|
+
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
789
1397
|
|
|
790
1398
|
headers = rb_easy_get("headers");
|
|
791
|
-
if( headers == Qnil ) {
|
|
1399
|
+
if( headers == Qnil ) {
|
|
792
1400
|
headers = rb_hash_new();
|
|
793
1401
|
}
|
|
794
1402
|
|
|
795
|
-
if (rb_respond_to(data, rb_intern("read"))) {
|
|
796
|
-
VALUE stat =
|
|
797
|
-
if
|
|
1403
|
+
if (!NIL_P(data) && rb_respond_to(data, rb_intern("read"))) {
|
|
1404
|
+
VALUE stat = Qnil;
|
|
1405
|
+
if (rb_respond_to(data, rb_intern("stat"))) {
|
|
1406
|
+
stat = rb_funcall(data, rb_intern("stat"), 0);
|
|
1407
|
+
}
|
|
1408
|
+
if(!NIL_P(stat) && stat != Qfalse && rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil) {
|
|
798
1409
|
VALUE size;
|
|
799
1410
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
|
800
1411
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
|
801
1412
|
}
|
|
802
1413
|
size = rb_funcall(stat, rb_intern("size"), 0);
|
|
803
|
-
|
|
1414
|
+
infile_size = size;
|
|
804
1415
|
}
|
|
805
1416
|
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
|
806
1417
|
rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
|
|
807
1418
|
}
|
|
808
1419
|
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) ) {
|
|
809
1420
|
VALUE size = rb_funcall(rb_hash_aref(headers, rb_str_new2("Content-Length")), rb_intern("to_i"), 0);
|
|
810
|
-
|
|
1421
|
+
infile_size = size;
|
|
811
1422
|
}
|
|
812
1423
|
}
|
|
813
|
-
else if (rb_respond_to(data, rb_intern("to_s"))) {
|
|
814
|
-
|
|
1424
|
+
else if (!NIL_P(data) && rb_respond_to(data, rb_intern("to_s"))) {
|
|
1425
|
+
infile_size = LONG2NUM(RSTRING_LEN(upload_stream));
|
|
815
1426
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
|
816
1427
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
|
817
1428
|
}
|
|
818
1429
|
}
|
|
1430
|
+
else if (NIL_P(data)) {
|
|
1431
|
+
/* Preserve legacy nil handling: configure an upload with no payload. */
|
|
1432
|
+
}
|
|
819
1433
|
else {
|
|
820
1434
|
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
|
821
1435
|
}
|
|
822
1436
|
rb_easy_set("headers",headers);
|
|
823
1437
|
|
|
1438
|
+
upload = ruby_curl_upload_new(cCurlUpload);
|
|
1439
|
+
ruby_curl_upload_stream_set(upload, upload_stream);
|
|
1440
|
+
|
|
1441
|
+
curl = rbce->curl;
|
|
1442
|
+
rb_easy_set("upload", upload); /* keep the upload object alive as long as
|
|
1443
|
+
the easy handle is active or until the upload
|
|
1444
|
+
is complete or terminated... */
|
|
1445
|
+
|
|
1446
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
|
1447
|
+
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
1448
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
|
1449
|
+
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
|
|
1450
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
|
1451
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
1452
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
1453
|
+
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
|
|
1454
|
+
#endif
|
|
1455
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
|
1456
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
1457
|
+
curl_easy_setopt(curl, CURLOPT_SEEKDATA, rbce);
|
|
1458
|
+
#endif
|
|
1459
|
+
|
|
1460
|
+
if (!NIL_P(infile_size)) {
|
|
1461
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, NUM2LONG(infile_size));
|
|
1462
|
+
}
|
|
1463
|
+
|
|
824
1464
|
// if we made it this far, all should be well.
|
|
825
1465
|
return data;
|
|
826
1466
|
}
|
|
@@ -829,20 +1469,47 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
829
1469
|
* call-seq:
|
|
830
1470
|
* easy.ftp_commands = ["CWD /", "MKD directory"] => ["CWD /", ...]
|
|
831
1471
|
*
|
|
832
|
-
* Explicitly sets the list of commands to execute on the FTP server when calling perform
|
|
1472
|
+
* Explicitly sets the list of commands to execute on the FTP server when calling perform.
|
|
1473
|
+
*
|
|
1474
|
+
* NOTE:
|
|
1475
|
+
* - This maps to libcurl CURLOPT_QUOTE; it sends commands on the control connection.
|
|
1476
|
+
* - Do not include data-transfer commands like LIST/NLST/RETR/STOR here. libcurl does not
|
|
1477
|
+
* parse PASV/EPSV replies from QUOTE commands and will not establish the required data
|
|
1478
|
+
* connection. For directory listings, set CURLOPT_DIRLISTONLY (via `easy.set(:dirlistonly, true)`)
|
|
1479
|
+
* and request an FTP directory URL (e.g. "ftp://host/path/") so libcurl manages PASV/EPSV
|
|
1480
|
+
* and the data connection for you.
|
|
833
1481
|
*/
|
|
834
1482
|
static VALUE ruby_curl_easy_ftp_commands_set(VALUE self, VALUE ftp_commands) {
|
|
835
1483
|
CURB_OBJECT_HSETTER(ruby_curl_easy, ftp_commands);
|
|
836
1484
|
}
|
|
837
1485
|
|
|
838
1486
|
/*
|
|
839
|
-
* call-seq
|
|
1487
|
+
* call-seq:
|
|
840
1488
|
* easy.ftp_commands => array or nil
|
|
841
1489
|
*/
|
|
842
1490
|
static VALUE ruby_curl_easy_ftp_commands_get(VALUE self) {
|
|
843
1491
|
CURB_OBJECT_HGETTER(ruby_curl_easy, ftp_commands);
|
|
844
1492
|
}
|
|
845
1493
|
|
|
1494
|
+
/*
|
|
1495
|
+
* call-seq:
|
|
1496
|
+
* easy.resolve = [ "example.com:80:127.0.0.1" ] => [ "example.com:80:127.0.0.1" ]
|
|
1497
|
+
*
|
|
1498
|
+
* Set the resolve list to statically resolve hostnames to IP addresses,
|
|
1499
|
+
* bypassing DNS for matching hostname/port combinations.
|
|
1500
|
+
*/
|
|
1501
|
+
static VALUE ruby_curl_easy_resolve_set(VALUE self, VALUE resolve) {
|
|
1502
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, resolve);
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
/*
|
|
1506
|
+
* call-seq:
|
|
1507
|
+
* easy.resolve => array or nil
|
|
1508
|
+
*/
|
|
1509
|
+
static VALUE ruby_curl_easy_resolve_get(VALUE self) {
|
|
1510
|
+
CURB_OBJECT_HGETTER(ruby_curl_easy, resolve);
|
|
1511
|
+
}
|
|
1512
|
+
|
|
846
1513
|
/* ================== IMMED ATTRS ==================*/
|
|
847
1514
|
|
|
848
1515
|
/*
|
|
@@ -951,16 +1618,16 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
|
|
|
951
1618
|
(!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
|
|
952
1619
|
(!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
|
|
953
1620
|
(!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
|
|
954
|
-
(!strncmp("
|
|
955
|
-
(!strncmp("
|
|
956
|
-
#else
|
|
1621
|
+
(!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
|
|
1622
|
+
(!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
|
|
1623
|
+
#else
|
|
957
1624
|
#define CURL_HTTPAUTH_STR_TO_NUM(node) \
|
|
958
1625
|
(!strncmp("basic",node,5)) ? CURLAUTH_BASIC : \
|
|
959
1626
|
(!strncmp("digest",node,6)) ? CURLAUTH_DIGEST : \
|
|
960
1627
|
(!strncmp("gssnegotiate",node,12)) ? CURLAUTH_GSSNEGOTIATE : \
|
|
961
1628
|
(!strncmp("ntlm",node,4)) ? CURLAUTH_NTLM : \
|
|
962
|
-
(!strncmp("
|
|
963
|
-
(!strncmp("
|
|
1629
|
+
(!strncmp("anysafe",node,7)) ? CURLAUTH_ANYSAFE : \
|
|
1630
|
+
(!strncmp("any",node,3)) ? CURLAUTH_ANY : 0
|
|
964
1631
|
#endif
|
|
965
1632
|
/*
|
|
966
1633
|
* call-seq:
|
|
@@ -974,21 +1641,22 @@ static VALUE ruby_curl_easy_proxy_type_get(VALUE self) {
|
|
|
974
1641
|
static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE self) {//VALUE self, VALUE http_auth_types) {
|
|
975
1642
|
ruby_curl_easy *rbce;
|
|
976
1643
|
VALUE args_ary;
|
|
977
|
-
|
|
1644
|
+
long i, len;
|
|
978
1645
|
char* node = NULL;
|
|
979
|
-
long mask =
|
|
1646
|
+
long mask = 0;
|
|
980
1647
|
|
|
981
1648
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
982
|
-
|
|
1649
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
983
1650
|
|
|
984
|
-
len =
|
|
1651
|
+
len = RARRAY_LEN(args_ary);
|
|
985
1652
|
|
|
986
|
-
if (len == 1 && (
|
|
987
|
-
|
|
1653
|
+
if (len == 1 && (rb_ary_entry(args_ary,0) == Qnil || TYPE(rb_ary_entry(args_ary,0)) == T_FIXNUM ||
|
|
1654
|
+
TYPE(rb_ary_entry(args_ary,0)) == T_BIGNUM)) {
|
|
1655
|
+
if (rb_ary_entry(args_ary,0) == Qnil) {
|
|
988
1656
|
rbce->http_auth_types = 0;
|
|
989
1657
|
}
|
|
990
1658
|
else {
|
|
991
|
-
rbce->http_auth_types =
|
|
1659
|
+
rbce->http_auth_types = NUM2LONG(rb_ary_entry(args_ary,0));
|
|
992
1660
|
}
|
|
993
1661
|
}
|
|
994
1662
|
else {
|
|
@@ -1001,7 +1669,7 @@ static VALUE ruby_curl_easy_http_auth_types_set(int argc, VALUE *argv, VALUE sel
|
|
|
1001
1669
|
}
|
|
1002
1670
|
rbce->http_auth_types = mask;
|
|
1003
1671
|
}
|
|
1004
|
-
return
|
|
1672
|
+
return LONG2NUM(rbce->http_auth_types);
|
|
1005
1673
|
}
|
|
1006
1674
|
|
|
1007
1675
|
/*
|
|
@@ -1066,7 +1734,7 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
|
1066
1734
|
|
|
1067
1735
|
/*
|
|
1068
1736
|
* call-seq:
|
|
1069
|
-
* easy.timeout = fixnum or nil
|
|
1737
|
+
* easy.timeout = float, fixnum or nil => numeric
|
|
1070
1738
|
*
|
|
1071
1739
|
* Set the maximum time in seconds that you allow the libcurl transfer
|
|
1072
1740
|
* operation to take. Normally, name lookups can take a considerable time
|
|
@@ -1075,20 +1743,77 @@ static VALUE ruby_curl_easy_max_redirects_get(VALUE self) {
|
|
|
1075
1743
|
*
|
|
1076
1744
|
* Set to nil (or zero) to disable timeout (it will then only timeout
|
|
1077
1745
|
* on the system's internal timeouts).
|
|
1746
|
+
*
|
|
1747
|
+
* Uses timeout_ms internally instead of timeout because it allows for
|
|
1748
|
+
* better precision and libcurl will use the last set value when both
|
|
1749
|
+
* timeout and timeout_ms are set.
|
|
1750
|
+
*
|
|
1078
1751
|
*/
|
|
1079
|
-
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE
|
|
1080
|
-
|
|
1752
|
+
static VALUE ruby_curl_easy_timeout_set(VALUE self, VALUE timeout_s) {
|
|
1753
|
+
ruby_curl_easy *rbce;
|
|
1754
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1755
|
+
|
|
1756
|
+
if (Qnil == timeout_s || NUM2DBL(timeout_s) <= 0.0) {
|
|
1757
|
+
rbce->timeout_ms = 0;
|
|
1758
|
+
} else {
|
|
1759
|
+
rbce->timeout_ms = (unsigned long)(NUM2DBL(timeout_s) * 1000);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
|
1081
1763
|
}
|
|
1082
1764
|
|
|
1083
1765
|
/*
|
|
1084
1766
|
* call-seq:
|
|
1085
|
-
* easy.timeout =>
|
|
1767
|
+
* easy.timeout => numeric
|
|
1086
1768
|
*
|
|
1087
1769
|
* Obtain the maximum time in seconds that you allow the libcurl transfer
|
|
1088
1770
|
* operation to take.
|
|
1771
|
+
*
|
|
1772
|
+
* Uses timeout_ms internally instead of timeout.
|
|
1773
|
+
*
|
|
1774
|
+
*/
|
|
1775
|
+
static VALUE ruby_curl_easy_timeout_get(VALUE self) {
|
|
1776
|
+
ruby_curl_easy *rbce;
|
|
1777
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1778
|
+
return DBL2NUM(rbce->timeout_ms / 1000.0);
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
/*
|
|
1782
|
+
* call-seq:
|
|
1783
|
+
* easy.timeout_ms = fixnum or nil => fixnum or nil
|
|
1784
|
+
*
|
|
1785
|
+
* Set the maximum time in milliseconds that you allow the libcurl transfer
|
|
1786
|
+
* operation to take. Normally, name lookups can take a considerable time
|
|
1787
|
+
* and limiting operations to less than a few minutes risk aborting
|
|
1788
|
+
* perfectly normal operations.
|
|
1789
|
+
*
|
|
1790
|
+
* Set to nil (or zero) to disable timeout (it will then only timeout
|
|
1791
|
+
* on the system's internal timeouts).
|
|
1792
|
+
*/
|
|
1793
|
+
static VALUE ruby_curl_easy_timeout_ms_set(VALUE self, VALUE timeout_ms) {
|
|
1794
|
+
ruby_curl_easy *rbce;
|
|
1795
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1796
|
+
|
|
1797
|
+
if (Qnil == timeout_ms || NUM2DBL(timeout_ms) <= 0.0) {
|
|
1798
|
+
rbce->timeout_ms = 0;
|
|
1799
|
+
} else {
|
|
1800
|
+
rbce->timeout_ms = NUM2ULONG(timeout_ms);
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
return ULONG2NUM(rbce->timeout_ms);
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
/*
|
|
1807
|
+
* call-seq:
|
|
1808
|
+
* easy.timeout_ms => fixnum or nil
|
|
1809
|
+
*
|
|
1810
|
+
* Obtain the maximum time in milliseconds that you allow the libcurl transfer
|
|
1811
|
+
* operation to take.
|
|
1089
1812
|
*/
|
|
1090
|
-
static VALUE
|
|
1091
|
-
|
|
1813
|
+
static VALUE ruby_curl_easy_timeout_ms_get(VALUE self) {
|
|
1814
|
+
ruby_curl_easy *rbce;
|
|
1815
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1816
|
+
return LONG2NUM(rbce->timeout_ms);
|
|
1092
1817
|
}
|
|
1093
1818
|
|
|
1094
1819
|
/*
|
|
@@ -1113,10 +1838,36 @@ static VALUE ruby_curl_easy_connect_timeout_set(VALUE self, VALUE connect_timeou
|
|
|
1113
1838
|
* Obtain the maximum time in seconds that you allow the connection to the
|
|
1114
1839
|
* server to take.
|
|
1115
1840
|
*/
|
|
1116
|
-
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self
|
|
1841
|
+
static VALUE ruby_curl_easy_connect_timeout_get(VALUE self) {
|
|
1117
1842
|
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout, 0);
|
|
1118
1843
|
}
|
|
1119
1844
|
|
|
1845
|
+
/*
|
|
1846
|
+
* call-seq:
|
|
1847
|
+
* easy.connect_timeout_ms = fixnum or nil => fixnum or nil
|
|
1848
|
+
*
|
|
1849
|
+
* Set the maximum time in milliseconds that you allow the connection to the
|
|
1850
|
+
* server to take. This only limits the connection phase, once it has
|
|
1851
|
+
* connected, this option is of no more use.
|
|
1852
|
+
*
|
|
1853
|
+
* Set to nil (or zero) to disable connection timeout (it will then only
|
|
1854
|
+
* timeout on the system's internal timeouts).
|
|
1855
|
+
*/
|
|
1856
|
+
static VALUE ruby_curl_easy_connect_timeout_ms_set(VALUE self, VALUE connect_timeout_ms) {
|
|
1857
|
+
CURB_IMMED_SETTER(ruby_curl_easy, connect_timeout_ms, 0);
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
/*
|
|
1861
|
+
* call-seq:
|
|
1862
|
+
* easy.connect_timeout_ms => fixnum or nil
|
|
1863
|
+
*
|
|
1864
|
+
* Obtain the maximum time in milliseconds that you allow the connection to the
|
|
1865
|
+
* server to take.
|
|
1866
|
+
*/
|
|
1867
|
+
static VALUE ruby_curl_easy_connect_timeout_ms_get(VALUE self) {
|
|
1868
|
+
CURB_IMMED_GETTER(ruby_curl_easy, connect_timeout_ms, 0);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1120
1871
|
/*
|
|
1121
1872
|
* call-seq:
|
|
1122
1873
|
* easy.dns_cache_timeout = fixnum or nil => fixnum or nil
|
|
@@ -1136,7 +1887,7 @@ static VALUE ruby_curl_easy_dns_cache_timeout_set(VALUE self, VALUE dns_cache_ti
|
|
|
1136
1887
|
*
|
|
1137
1888
|
* Obtain the dns cache timeout in seconds.
|
|
1138
1889
|
*/
|
|
1139
|
-
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self
|
|
1890
|
+
static VALUE ruby_curl_easy_dns_cache_timeout_get(VALUE self) {
|
|
1140
1891
|
CURB_IMMED_GETTER(ruby_curl_easy, dns_cache_timeout, -1);
|
|
1141
1892
|
}
|
|
1142
1893
|
|
|
@@ -1163,7 +1914,7 @@ static VALUE ruby_curl_easy_ftp_response_timeout_set(VALUE self, VALUE ftp_respo
|
|
|
1163
1914
|
*
|
|
1164
1915
|
* Obtain the maximum time that libcurl will wait for FTP command responses.
|
|
1165
1916
|
*/
|
|
1166
|
-
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self
|
|
1917
|
+
static VALUE ruby_curl_easy_ftp_response_timeout_get(VALUE self) {
|
|
1167
1918
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_response_timeout, 0);
|
|
1168
1919
|
}
|
|
1169
1920
|
|
|
@@ -1186,7 +1937,7 @@ static VALUE ruby_curl_easy_low_speed_limit_set(VALUE self, VALUE low_speed_limi
|
|
|
1186
1937
|
* Obtain the minimum transfer speed over +low_speed+time+ below which the
|
|
1187
1938
|
* transfer will be aborted.
|
|
1188
1939
|
*/
|
|
1189
|
-
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self
|
|
1940
|
+
static VALUE ruby_curl_easy_low_speed_limit_get(VALUE self) {
|
|
1190
1941
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_limit, 0);
|
|
1191
1942
|
}
|
|
1192
1943
|
|
|
@@ -1208,10 +1959,50 @@ static VALUE ruby_curl_easy_low_speed_time_set(VALUE self, VALUE low_speed_time)
|
|
|
1208
1959
|
* Obtain the time that the transfer should be below +low_speed_limit+ for
|
|
1209
1960
|
* the library to abort it.
|
|
1210
1961
|
*/
|
|
1211
|
-
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self
|
|
1962
|
+
static VALUE ruby_curl_easy_low_speed_time_get(VALUE self) {
|
|
1212
1963
|
CURB_IMMED_GETTER(ruby_curl_easy, low_speed_time, 0);
|
|
1213
1964
|
}
|
|
1214
1965
|
|
|
1966
|
+
/*
|
|
1967
|
+
* call-seq:
|
|
1968
|
+
* easy.max_send_speed_large = fixnum or nil => fixnum or nil
|
|
1969
|
+
*
|
|
1970
|
+
* Set the maximal sending transfer speed (in bytes per second)
|
|
1971
|
+
*/
|
|
1972
|
+
static VALUE ruby_curl_easy_max_send_speed_large_set(VALUE self, VALUE max_send_speed_large) {
|
|
1973
|
+
CURB_IMMED_SETTER(ruby_curl_easy, max_send_speed_large, 0);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/*
|
|
1977
|
+
* call-seq:
|
|
1978
|
+
* easy.max_send_speed_large = fixnum or nil => fixnum or nil
|
|
1979
|
+
*
|
|
1980
|
+
* Get the maximal sending transfer speed (in bytes per second)
|
|
1981
|
+
*/
|
|
1982
|
+
static VALUE ruby_curl_easy_max_send_speed_large_get(VALUE self) {
|
|
1983
|
+
CURB_IMMED_GETTER(ruby_curl_easy, max_send_speed_large, 0);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
/*
|
|
1987
|
+
* call-seq:
|
|
1988
|
+
* easy.max_recv_speed_large = fixnum or nil => fixnum or nil
|
|
1989
|
+
*
|
|
1990
|
+
* Set the maximal receiving transfer speed (in bytes per second)
|
|
1991
|
+
*/
|
|
1992
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_set(VALUE self, VALUE max_recv_speed_large) {
|
|
1993
|
+
CURB_IMMED_SETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
|
1994
|
+
}
|
|
1995
|
+
|
|
1996
|
+
/*
|
|
1997
|
+
* call-seq:
|
|
1998
|
+
* easy.max_recv_speed_large = fixnum or nil => fixnum or nil
|
|
1999
|
+
*
|
|
2000
|
+
* Get the maximal receiving transfer speed (in bytes per second)
|
|
2001
|
+
*/
|
|
2002
|
+
static VALUE ruby_curl_easy_max_recv_speed_large_get(VALUE self) {
|
|
2003
|
+
CURB_IMMED_GETTER(ruby_curl_easy, max_recv_speed_large, 0);
|
|
2004
|
+
}
|
|
2005
|
+
|
|
1215
2006
|
/*
|
|
1216
2007
|
* call-seq:
|
|
1217
2008
|
* easy.username = string => string
|
|
@@ -1219,7 +2010,7 @@ static VALUE ruby_curl_easy_low_speed_time_get(VALUE self, VALUE low_speed_time)
|
|
|
1219
2010
|
* Set the HTTP Authentication username.
|
|
1220
2011
|
*/
|
|
1221
2012
|
static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
|
|
1222
|
-
#
|
|
2013
|
+
#ifdef HAVE_CURLOPT_USERNAME
|
|
1223
2014
|
CURB_OBJECT_HSETTER(ruby_curl_easy, username);
|
|
1224
2015
|
#else
|
|
1225
2016
|
return Qnil;
|
|
@@ -1229,11 +2020,11 @@ static VALUE ruby_curl_easy_username_set(VALUE self, VALUE username) {
|
|
|
1229
2020
|
/*
|
|
1230
2021
|
* call-seq:
|
|
1231
2022
|
* easy.username => string
|
|
1232
|
-
*
|
|
2023
|
+
*
|
|
1233
2024
|
* Get the current username
|
|
1234
2025
|
*/
|
|
1235
|
-
static VALUE ruby_curl_easy_username_get(VALUE self
|
|
1236
|
-
#
|
|
2026
|
+
static VALUE ruby_curl_easy_username_get(VALUE self) {
|
|
2027
|
+
#ifdef HAVE_CURLOPT_USERNAME
|
|
1237
2028
|
CURB_OBJECT_HGETTER(ruby_curl_easy, username);
|
|
1238
2029
|
#else
|
|
1239
2030
|
return Qnil;
|
|
@@ -1247,7 +2038,7 @@ static VALUE ruby_curl_easy_username_get(VALUE self, VALUE username) {
|
|
|
1247
2038
|
* Set the HTTP Authentication password.
|
|
1248
2039
|
*/
|
|
1249
2040
|
static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
|
|
1250
|
-
#
|
|
2041
|
+
#ifdef HAVE_CURLOPT_PASSWORD
|
|
1251
2042
|
CURB_OBJECT_HSETTER(ruby_curl_easy, password);
|
|
1252
2043
|
#else
|
|
1253
2044
|
return Qnil;
|
|
@@ -1257,11 +2048,11 @@ static VALUE ruby_curl_easy_password_set(VALUE self, VALUE password) {
|
|
|
1257
2048
|
/*
|
|
1258
2049
|
* call-seq:
|
|
1259
2050
|
* easy.password => string
|
|
1260
|
-
*
|
|
2051
|
+
*
|
|
1261
2052
|
* Get the current password
|
|
1262
2053
|
*/
|
|
1263
|
-
static VALUE ruby_curl_easy_password_get(VALUE self
|
|
1264
|
-
#
|
|
2054
|
+
static VALUE ruby_curl_easy_password_get(VALUE self) {
|
|
2055
|
+
#ifdef HAVE_CURLOPT_PASSWORD
|
|
1265
2056
|
CURB_OBJECT_HGETTER(ruby_curl_easy, password);
|
|
1266
2057
|
#else
|
|
1267
2058
|
return Qnil;
|
|
@@ -1273,8 +2064,16 @@ static VALUE ruby_curl_easy_password_get(VALUE self, VALUE password) {
|
|
|
1273
2064
|
* easy.ssl_version = value => fixnum or nil
|
|
1274
2065
|
*
|
|
1275
2066
|
* Sets the version of SSL/TLS that libcurl will attempt to use. Valid
|
|
1276
|
-
* options are
|
|
1277
|
-
*
|
|
2067
|
+
* options are:
|
|
2068
|
+
*
|
|
2069
|
+
* Curl::CURL_SSLVERSION_DEFAULT
|
|
2070
|
+
* Curl::CURL_SSLVERSION_TLSv1 (TLS 1.x)
|
|
2071
|
+
* Curl::CURL_SSLVERSION_SSLv2
|
|
2072
|
+
* Curl::CURL_SSLVERSION_SSLv3
|
|
2073
|
+
* Curl::CURL_SSLVERSION_TLSv1_0
|
|
2074
|
+
* Curl::CURL_SSLVERSION_TLSv1_1
|
|
2075
|
+
* Curl::CURL_SSLVERSION_TLSv1_2
|
|
2076
|
+
* Curl::CURL_SSLVERSION_TLSv1_3
|
|
1278
2077
|
*/
|
|
1279
2078
|
static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
|
1280
2079
|
CURB_IMMED_SETTER(ruby_curl_easy, ssl_version, -1);
|
|
@@ -1286,14 +2085,14 @@ static VALUE ruby_curl_easy_ssl_version_set(VALUE self, VALUE ssl_version) {
|
|
|
1286
2085
|
*
|
|
1287
2086
|
* Get the version of SSL/TLS that libcurl will attempt to use.
|
|
1288
2087
|
*/
|
|
1289
|
-
static VALUE ruby_curl_easy_ssl_version_get(VALUE self
|
|
2088
|
+
static VALUE ruby_curl_easy_ssl_version_get(VALUE self) {
|
|
1290
2089
|
CURB_IMMED_GETTER(ruby_curl_easy, ssl_version, -1);
|
|
1291
2090
|
}
|
|
1292
2091
|
|
|
1293
2092
|
/*
|
|
1294
2093
|
* call-seq:
|
|
1295
2094
|
* easy.use_ssl = value => fixnum or nil
|
|
1296
|
-
*
|
|
2095
|
+
*
|
|
1297
2096
|
* Ensure libcurl uses SSL for FTP connections. Valid options are Curl::CURL_USESSL_NONE,
|
|
1298
2097
|
* Curl::CURL_USESSL_TRY, Curl::CURL_USESSL_CONTROL, and Curl::CURL_USESSL_ALL.
|
|
1299
2098
|
*/
|
|
@@ -1307,7 +2106,7 @@ static VALUE ruby_curl_easy_use_ssl_set(VALUE self, VALUE use_ssl) {
|
|
|
1307
2106
|
*
|
|
1308
2107
|
* Get the desired level for using SSL on FTP connections.
|
|
1309
2108
|
*/
|
|
1310
|
-
static VALUE ruby_curl_easy_use_ssl_get(VALUE self
|
|
2109
|
+
static VALUE ruby_curl_easy_use_ssl_get(VALUE self) {
|
|
1311
2110
|
CURB_IMMED_GETTER(ruby_curl_easy, use_ssl, -1);
|
|
1312
2111
|
}
|
|
1313
2112
|
|
|
@@ -1323,12 +2122,12 @@ static VALUE ruby_curl_easy_ftp_filemethod_set(VALUE self, VALUE ftp_filemethod)
|
|
|
1323
2122
|
}
|
|
1324
2123
|
|
|
1325
2124
|
/*
|
|
1326
|
-
* call-seq
|
|
2125
|
+
* call-seq:
|
|
1327
2126
|
* easy.ftp_filemethod => fixnum
|
|
1328
2127
|
*
|
|
1329
2128
|
* Get the configuration for how libcurl will reach files on the server.
|
|
1330
2129
|
*/
|
|
1331
|
-
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self
|
|
2130
|
+
static VALUE ruby_curl_easy_ftp_filemethod_get(VALUE self) {
|
|
1332
2131
|
CURB_IMMED_GETTER(ruby_curl_easy, ftp_filemethod, -1);
|
|
1333
2132
|
}
|
|
1334
2133
|
|
|
@@ -1486,7 +2285,7 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
|
|
|
1486
2285
|
*/
|
|
1487
2286
|
static VALUE ruby_curl_easy_autoreferer_set(VALUE self, VALUE autoreferer) {
|
|
1488
2287
|
ruby_curl_easy *rbce;
|
|
1489
|
-
|
|
2288
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1490
2289
|
|
|
1491
2290
|
if (Qtrue == autoreferer) {
|
|
1492
2291
|
curl_easy_setopt(rbce->curl, CURLOPT_AUTOREFERER, 1);
|
|
@@ -1587,7 +2386,12 @@ static VALUE ruby_curl_easy_multipart_form_post_q(VALUE self) {
|
|
|
1587
2386
|
* easy.enable_cookies = boolean => boolean
|
|
1588
2387
|
*
|
|
1589
2388
|
* Configure whether the libcurl cookie engine is enabled for this Curl::Easy
|
|
1590
|
-
* instance.
|
|
2389
|
+
* instance. When enabled, cookies received via Set-Cookie are stored by libcurl
|
|
2390
|
+
* and automatically sent on subsequent matching requests. Use +easy.cookiefile+
|
|
2391
|
+
* to load cookies and +easy.cookiejar+ to persist them.
|
|
2392
|
+
*
|
|
2393
|
+
* This setting is independent from the manual Cookie header set via +easy.cookies+.
|
|
2394
|
+
* The manual header is additive and can be cleared by assigning an empty string.
|
|
1591
2395
|
*/
|
|
1592
2396
|
static VALUE ruby_curl_easy_enable_cookies_set(VALUE self, VALUE enable_cookies)
|
|
1593
2397
|
{
|
|
@@ -1637,9 +2441,10 @@ static VALUE ruby_curl_easy_ignore_content_length_q(VALUE self) {
|
|
|
1637
2441
|
*/
|
|
1638
2442
|
static VALUE ruby_curl_easy_resolve_mode(VALUE self) {
|
|
1639
2443
|
ruby_curl_easy *rbce;
|
|
1640
|
-
|
|
2444
|
+
unsigned short rm;
|
|
2445
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1641
2446
|
|
|
1642
|
-
|
|
2447
|
+
rm = rbce->resolve_mode;
|
|
1643
2448
|
|
|
1644
2449
|
switch(rm) {
|
|
1645
2450
|
case CURL_IPRESOLVE_V4:
|
|
@@ -1668,9 +2473,10 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
|
1668
2473
|
return Qnil;
|
|
1669
2474
|
} else {
|
|
1670
2475
|
ruby_curl_easy *rbce;
|
|
1671
|
-
|
|
2476
|
+
ID resolve_mode_id;
|
|
2477
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1672
2478
|
|
|
1673
|
-
|
|
2479
|
+
resolve_mode_id = rb_to_id(resolve_mode);
|
|
1674
2480
|
|
|
1675
2481
|
if (resolve_mode_id == rb_intern("auto")) {
|
|
1676
2482
|
rbce->resolve_mode = CURL_IPRESOLVE_WHATEVER;
|
|
@@ -1688,12 +2494,52 @@ static VALUE ruby_curl_easy_resolve_mode_set(VALUE self, VALUE resolve_mode) {
|
|
|
1688
2494
|
}
|
|
1689
2495
|
}
|
|
1690
2496
|
|
|
2497
|
+
/*
|
|
2498
|
+
* call-seq:
|
|
2499
|
+
* easy.http_version = Curl::HTTP_1_1 => Curl::HTTP_1_1
|
|
2500
|
+
*
|
|
2501
|
+
* Force libcurl to use a specific HTTP protocol version. By default libcurl
|
|
2502
|
+
* negotiates the highest version supported by both peers. Supported constants
|
|
2503
|
+
* include Curl::HTTP_NONE, Curl::HTTP_1_0, Curl::HTTP_1_1, Curl::HTTP_2_0,
|
|
2504
|
+
* Curl::HTTP_2TLS, and Curl::HTTP_2_PRIOR_KNOWLEDGE (when provided by libcurl).
|
|
2505
|
+
*/
|
|
2506
|
+
static VALUE ruby_curl_easy_http_version_set(VALUE self, VALUE version) {
|
|
2507
|
+
ruby_curl_easy *rbce;
|
|
2508
|
+
long http_version;
|
|
2509
|
+
|
|
2510
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2511
|
+
|
|
2512
|
+
if (NIL_P(version)) {
|
|
2513
|
+
http_version = CURL_HTTP_VERSION_NONE;
|
|
2514
|
+
} else {
|
|
2515
|
+
http_version = NUM2LONG(version);
|
|
2516
|
+
}
|
|
2517
|
+
|
|
2518
|
+
rbce->http_version = http_version;
|
|
2519
|
+
|
|
2520
|
+
return version;
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
/*
|
|
2524
|
+
* call-seq:
|
|
2525
|
+
* easy.http_version => integer
|
|
2526
|
+
*
|
|
2527
|
+
* Returns the HTTP protocol version currently configured.
|
|
2528
|
+
*/
|
|
2529
|
+
static VALUE ruby_curl_easy_http_version_get(VALUE self) {
|
|
2530
|
+
ruby_curl_easy *rbce;
|
|
2531
|
+
|
|
2532
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2533
|
+
|
|
2534
|
+
return LONG2NUM(rbce->http_version);
|
|
2535
|
+
}
|
|
2536
|
+
|
|
1691
2537
|
|
|
1692
2538
|
/* ================= EVENT PROCS ================== */
|
|
1693
2539
|
|
|
1694
2540
|
/*
|
|
1695
2541
|
* call-seq:
|
|
1696
|
-
* easy.on_body { |body_data| ... } =>
|
|
2542
|
+
* easy.on_body { |body_data| ... } => <old handler>
|
|
1697
2543
|
*
|
|
1698
2544
|
* Assign or remove the +on_body+ handler for this Curl::Easy instance.
|
|
1699
2545
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1712,7 +2558,7 @@ static VALUE ruby_curl_easy_on_body_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1712
2558
|
|
|
1713
2559
|
/*
|
|
1714
2560
|
* call-seq:
|
|
1715
|
-
* easy.on_success { |easy| ... } =>
|
|
2561
|
+
* easy.on_success { |easy| ... } => <old handler>
|
|
1716
2562
|
*
|
|
1717
2563
|
* Assign or remove the +on_success+ handler for this Curl::Easy instance.
|
|
1718
2564
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1727,7 +2573,7 @@ static VALUE ruby_curl_easy_on_success_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1727
2573
|
|
|
1728
2574
|
/*
|
|
1729
2575
|
* call-seq:
|
|
1730
|
-
* easy.on_failure {|easy,code| ... } =>
|
|
2576
|
+
* easy.on_failure {|easy,code| ... } => <old handler>
|
|
1731
2577
|
*
|
|
1732
2578
|
* Assign or remove the +on_failure+ handler for this Curl::Easy instance.
|
|
1733
2579
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1742,13 +2588,13 @@ static VALUE ruby_curl_easy_on_failure_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1742
2588
|
|
|
1743
2589
|
/*
|
|
1744
2590
|
* call-seq:
|
|
1745
|
-
* easy.on_missing {|easy,code| ... } =>
|
|
2591
|
+
* easy.on_missing {|easy,code| ... } => <old handler;>
|
|
1746
2592
|
*
|
|
1747
2593
|
* Assign or remove the on_missing handler for this Curl::Easy instance.
|
|
1748
2594
|
* To remove a previously-supplied handler, call this method with no attached
|
|
1749
2595
|
* block.
|
|
1750
2596
|
*
|
|
1751
|
-
* The +on_missing+ handler is called when request is finished with a
|
|
2597
|
+
* The +on_missing+ handler is called when request is finished with a
|
|
1752
2598
|
* status of 40x
|
|
1753
2599
|
*/
|
|
1754
2600
|
static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1757,13 +2603,13 @@ static VALUE ruby_curl_easy_on_missing_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1757
2603
|
|
|
1758
2604
|
/*
|
|
1759
2605
|
* call-seq:
|
|
1760
|
-
* easy.on_redirect {|easy,code| ... } =>
|
|
2606
|
+
* easy.on_redirect {|easy,code| ... } => <old handler;>
|
|
1761
2607
|
*
|
|
1762
2608
|
* Assign or remove the on_redirect handler for this Curl::Easy instance.
|
|
1763
2609
|
* To remove a previously-supplied handler, call this method with no attached
|
|
1764
2610
|
* block.
|
|
1765
2611
|
*
|
|
1766
|
-
* The +on_redirect+ handler is called when request is finished with a
|
|
2612
|
+
* The +on_redirect+ handler is called when request is finished with a
|
|
1767
2613
|
* status of 30x
|
|
1768
2614
|
*/
|
|
1769
2615
|
static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
@@ -1772,7 +2618,7 @@ static VALUE ruby_curl_easy_on_redirect_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1772
2618
|
|
|
1773
2619
|
/*
|
|
1774
2620
|
* call-seq:
|
|
1775
|
-
* easy.on_complete {|easy| ... } =>
|
|
2621
|
+
* easy.on_complete {|easy| ... } => <old handler>
|
|
1776
2622
|
*
|
|
1777
2623
|
* Assign or remove the +on_complete+ handler for this Curl::Easy instance.
|
|
1778
2624
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1786,7 +2632,7 @@ static VALUE ruby_curl_easy_on_complete_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1786
2632
|
|
|
1787
2633
|
/*
|
|
1788
2634
|
* call-seq:
|
|
1789
|
-
* easy.on_header { |header_data| ... } =>
|
|
2635
|
+
* easy.on_header { |header_data| ... } => <old handler>
|
|
1790
2636
|
*
|
|
1791
2637
|
* Assign or remove the +on_header+ handler for this Curl::Easy instance.
|
|
1792
2638
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1802,7 +2648,7 @@ static VALUE ruby_curl_easy_on_header_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1802
2648
|
|
|
1803
2649
|
/*
|
|
1804
2650
|
* call-seq:
|
|
1805
|
-
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } =>
|
|
2651
|
+
* easy.on_progress { |dl_total, dl_now, ul_total, ul_now| ... } => <old handler>
|
|
1806
2652
|
*
|
|
1807
2653
|
* Assign or remove the +on_progress+ handler for this Curl::Easy instance.
|
|
1808
2654
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1823,7 +2669,7 @@ static VALUE ruby_curl_easy_on_progress_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1823
2669
|
|
|
1824
2670
|
/*
|
|
1825
2671
|
* call-seq:
|
|
1826
|
-
* easy.on_debug { |type, data| ... } =>
|
|
2672
|
+
* easy.on_debug { |type, data| ... } => <old handler>
|
|
1827
2673
|
*
|
|
1828
2674
|
* Assign or remove the +on_debug+ handler for this Curl::Easy instance.
|
|
1829
2675
|
* To remove a previously-supplied handler, call this method with no
|
|
@@ -1848,12 +2694,12 @@ static VALUE ruby_curl_easy_on_debug_set(int argc, VALUE *argv, VALUE self) {
|
|
|
1848
2694
|
/***********************************************
|
|
1849
2695
|
* This is an rb_iterate callback used to set up http headers.
|
|
1850
2696
|
*/
|
|
1851
|
-
static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
2697
|
+
static VALUE cb_each_http_header(VALUE header, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
1852
2698
|
struct curl_slist **list;
|
|
1853
|
-
Data_Get_Struct(wrap, struct curl_slist *, list);
|
|
1854
|
-
|
|
1855
2699
|
VALUE header_str = Qnil;
|
|
1856
2700
|
|
|
2701
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
2702
|
+
|
|
1857
2703
|
//rb_p(header);
|
|
1858
2704
|
|
|
1859
2705
|
if (rb_type(header) == T_ARRAY) {
|
|
@@ -1862,34 +2708,100 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap) {
|
|
|
1862
2708
|
|
|
1863
2709
|
name = rb_obj_as_string(rb_ary_entry(header, 0));
|
|
1864
2710
|
value = rb_obj_as_string(rb_ary_entry(header, 1));
|
|
2711
|
+
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
|
|
2712
|
+
header_str = rb_str_plus(name, rb_str_new2(":"));
|
|
2713
|
+
} else {
|
|
2714
|
+
// This is a bit inefficient, but we don't want to be modifying
|
|
2715
|
+
// the actual values in the original hash.
|
|
2716
|
+
header_str = rb_str_plus(name, rb_str_new2(": "));
|
|
2717
|
+
header_str = rb_str_plus(header_str, value);
|
|
2718
|
+
}
|
|
2719
|
+
} else {
|
|
2720
|
+
header_str = rb_obj_as_string(header);
|
|
2721
|
+
}
|
|
2722
|
+
|
|
2723
|
+
//rb_p(header_str);
|
|
2724
|
+
|
|
2725
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(header_str));
|
|
2726
|
+
if (!new_list) {
|
|
2727
|
+
rb_raise(rb_eNoMemError, "Failed to append to header list");
|
|
2728
|
+
}
|
|
2729
|
+
*list = new_list;
|
|
2730
|
+
return header_str;
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
/***********************************************
|
|
2734
|
+
* This is an rb_iterate callback used to set up http proxy headers.
|
|
2735
|
+
*/
|
|
2736
|
+
static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
2737
|
+
struct curl_slist **list;
|
|
2738
|
+
VALUE proxy_header_str = Qnil;
|
|
2739
|
+
|
|
2740
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
2741
|
+
|
|
2742
|
+
//rb_p(proxy_header);
|
|
2743
|
+
|
|
2744
|
+
if (rb_type(proxy_header) == T_ARRAY) {
|
|
2745
|
+
// we're processing a hash, proxy header is [name, val]
|
|
2746
|
+
VALUE name, value;
|
|
2747
|
+
|
|
2748
|
+
name = rb_obj_as_string(rb_ary_entry(proxy_header, 0));
|
|
2749
|
+
value = rb_obj_as_string(rb_ary_entry(proxy_header, 1));
|
|
1865
2750
|
|
|
1866
2751
|
// This is a bit inefficient, but we don't want to be modifying
|
|
1867
2752
|
// the actual values in the original hash.
|
|
1868
|
-
|
|
1869
|
-
|
|
2753
|
+
proxy_header_str = rb_str_plus(name, rb_str_new2(": "));
|
|
2754
|
+
proxy_header_str = rb_str_plus(proxy_header_str, value);
|
|
1870
2755
|
} else {
|
|
1871
|
-
|
|
2756
|
+
proxy_header_str = rb_obj_as_string(proxy_header);
|
|
1872
2757
|
}
|
|
1873
2758
|
|
|
1874
2759
|
//rb_p(header_str);
|
|
1875
2760
|
|
|
1876
|
-
*
|
|
1877
|
-
|
|
2761
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
|
|
2762
|
+
if (!new_list) {
|
|
2763
|
+
rb_raise(rb_eNoMemError, "Failed to append to proxy header list");
|
|
2764
|
+
}
|
|
2765
|
+
*list = new_list;
|
|
2766
|
+
return proxy_header_str;
|
|
1878
2767
|
}
|
|
1879
2768
|
|
|
1880
2769
|
/***********************************************
|
|
1881
2770
|
* This is an rb_iterate callback used to set up ftp commands.
|
|
1882
2771
|
*/
|
|
1883
|
-
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
|
2772
|
+
static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
1884
2773
|
struct curl_slist **list;
|
|
1885
|
-
|
|
2774
|
+
VALUE ftp_command_string;
|
|
2775
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
1886
2776
|
|
|
1887
|
-
|
|
1888
|
-
*
|
|
2777
|
+
ftp_command_string = rb_obj_as_string(ftp_command);
|
|
2778
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(ftp_command_string));
|
|
2779
|
+
if (!new_list) {
|
|
2780
|
+
rb_raise(rb_eNoMemError, "Failed to append to FTP command list");
|
|
2781
|
+
}
|
|
2782
|
+
*list = new_list;
|
|
1889
2783
|
|
|
1890
2784
|
return ftp_command_string;
|
|
1891
2785
|
}
|
|
1892
2786
|
|
|
2787
|
+
/***********************************************
|
|
2788
|
+
* This is an rb_iterate callback used to set up the resolve list.
|
|
2789
|
+
*/
|
|
2790
|
+
static VALUE cb_each_resolve(VALUE resolve, VALUE wrap, int _c, const VALUE *_ptr, VALUE unused) {
|
|
2791
|
+
struct curl_slist **list;
|
|
2792
|
+
VALUE resolve_string;
|
|
2793
|
+
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
2794
|
+
|
|
2795
|
+
resolve_string = rb_obj_as_string(resolve);
|
|
2796
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(resolve_string));
|
|
2797
|
+
if (!new_list) {
|
|
2798
|
+
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
2799
|
+
}
|
|
2800
|
+
*list = new_list;
|
|
2801
|
+
|
|
2802
|
+
return resolve_string;
|
|
2803
|
+
}
|
|
2804
|
+
|
|
1893
2805
|
/***********************************************
|
|
1894
2806
|
*
|
|
1895
2807
|
* Setup a connection
|
|
@@ -1901,16 +2813,18 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1901
2813
|
CURL *curl;
|
|
1902
2814
|
VALUE url, _url = rb_easy_get("url");
|
|
1903
2815
|
struct curl_slist **hdrs = &(rbce->curl_headers);
|
|
2816
|
+
struct curl_slist **phdrs = &(rbce->curl_proxy_headers);
|
|
1904
2817
|
struct curl_slist **cmds = &(rbce->curl_ftp_commands);
|
|
2818
|
+
struct curl_slist **rslv = &(rbce->curl_resolve);
|
|
1905
2819
|
|
|
1906
2820
|
curl = rbce->curl;
|
|
2821
|
+
rbce->callback_error = Qnil;
|
|
1907
2822
|
|
|
1908
2823
|
if (_url == Qnil) {
|
|
1909
2824
|
rb_raise(eCurlErrError, "No URL supplied");
|
|
1910
2825
|
}
|
|
1911
2826
|
|
|
1912
2827
|
url = rb_check_string_type(_url);
|
|
1913
|
-
|
|
1914
2828
|
curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
|
|
1915
2829
|
|
|
1916
2830
|
// network stuff and auth
|
|
@@ -1920,7 +2834,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1920
2834
|
curl_easy_setopt(curl, CURLOPT_INTERFACE, NULL);
|
|
1921
2835
|
}
|
|
1922
2836
|
|
|
1923
|
-
#if HAVE_CURLOPT_USERNAME
|
|
2837
|
+
#if defined(HAVE_CURLOPT_USERNAME) && defined(HAVE_CURLOPT_PASSWORD)
|
|
1924
2838
|
if (!rb_easy_nil("username")) {
|
|
1925
2839
|
curl_easy_setopt(curl, CURLOPT_USERNAME, rb_easy_get_str("username"));
|
|
1926
2840
|
} else {
|
|
@@ -1936,7 +2850,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1936
2850
|
|
|
1937
2851
|
if (!rb_easy_nil("userpwd")) {
|
|
1938
2852
|
curl_easy_setopt(curl, CURLOPT_USERPWD, rb_easy_get_str("userpwd"));
|
|
1939
|
-
#if HAVE_CURLOPT_USERNAME
|
|
2853
|
+
#if defined(HAVE_CURLOPT_USERNAME) && defined(HAVE_CURLOPT_PASSWORD)
|
|
1940
2854
|
} 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
2855
|
#else
|
|
1942
2856
|
} else {
|
|
@@ -1956,6 +2870,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1956
2870
|
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
|
|
1957
2871
|
}
|
|
1958
2872
|
|
|
2873
|
+
#ifdef HAVE_CURLOPT_NOPROXY
|
|
2874
|
+
if (rb_easy_nil("noproxy")) {
|
|
2875
|
+
curl_easy_setopt(curl, CURLOPT_NOPROXY, NULL);
|
|
2876
|
+
} else {
|
|
2877
|
+
curl_easy_setopt(curl, CURLOPT_NOPROXY, rb_easy_get_str("noproxy"));
|
|
2878
|
+
}
|
|
2879
|
+
#endif
|
|
2880
|
+
|
|
1959
2881
|
// body/header procs
|
|
1960
2882
|
if (!rb_easy_nil("body_proc")) {
|
|
1961
2883
|
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
|
|
@@ -1963,9 +2885,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1963
2885
|
/* clear out the body_data if it was set */
|
|
1964
2886
|
rb_easy_del("body_data");
|
|
1965
2887
|
} else {
|
|
1966
|
-
|
|
1967
|
-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&
|
|
1968
|
-
curl_easy_setopt(curl, CURLOPT_WRITEDATA,
|
|
2888
|
+
rb_easy_set("body_data", rb_str_buf_new(32768));
|
|
2889
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&default_body_handler);
|
|
2890
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
|
|
1969
2891
|
}
|
|
1970
2892
|
|
|
1971
2893
|
if (!rb_easy_nil("header_proc")) {
|
|
@@ -1974,9 +2896,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1974
2896
|
/* clear out the header_data if it was set */
|
|
1975
2897
|
rb_easy_del("header_data");
|
|
1976
2898
|
} else {
|
|
1977
|
-
|
|
1978
|
-
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&
|
|
1979
|
-
curl_easy_setopt(curl, CURLOPT_HEADERDATA,
|
|
2899
|
+
rb_easy_set("header_data", rb_str_buf_new(16384));
|
|
2900
|
+
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&default_header_handler);
|
|
2901
|
+
curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
|
|
1980
2902
|
}
|
|
1981
2903
|
|
|
1982
2904
|
/* encoding */
|
|
@@ -1986,21 +2908,31 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
1986
2908
|
|
|
1987
2909
|
// progress and debug procs
|
|
1988
2910
|
if (!rb_easy_nil("progress_proc")) {
|
|
2911
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
2912
|
+
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, &proc_xferinfo_handler);
|
|
2913
|
+
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, rbce);
|
|
2914
|
+
#else
|
|
1989
2915
|
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, (curl_progress_callback)&proc_progress_handler);
|
|
1990
|
-
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA,
|
|
2916
|
+
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce);
|
|
2917
|
+
#endif
|
|
1991
2918
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
|
1992
2919
|
} else {
|
|
1993
2920
|
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
|
2921
|
+
#ifdef HAVE_CURLOPT_XFERINFOFUNCTION
|
|
2922
|
+
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, rbce);
|
|
2923
|
+
#else
|
|
2924
|
+
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, rbce);
|
|
2925
|
+
#endif
|
|
1994
2926
|
}
|
|
1995
2927
|
|
|
1996
2928
|
if (!rb_easy_nil("debug_proc")) {
|
|
1997
2929
|
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, (curl_debug_callback)&proc_debug_handler);
|
|
1998
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGDATA,
|
|
2930
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce);
|
|
1999
2931
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
|
2000
2932
|
} else {
|
|
2001
2933
|
// have to remove handler to re-enable standard verbosity
|
|
2002
2934
|
curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, NULL);
|
|
2003
|
-
curl_easy_setopt(curl, CURLOPT_DEBUGDATA,
|
|
2935
|
+
curl_easy_setopt(curl, CURLOPT_DEBUGDATA, rbce);
|
|
2004
2936
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, rbce->verbose);
|
|
2005
2937
|
}
|
|
2006
2938
|
|
|
@@ -2008,7 +2940,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2008
2940
|
|
|
2009
2941
|
curl_easy_setopt(curl, CURLOPT_HEADER, rbce->header_in_body);
|
|
2010
2942
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, rbce->follow_location);
|
|
2943
|
+
#if LIBCURL_VERSION_NUM == 0x081000
|
|
2944
|
+
/* Work around 8.16.0 regression that clamps -1 (infinite) to zero */
|
|
2945
|
+
if (rbce->max_redirs >= 0) {
|
|
2946
|
+
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
2947
|
+
}
|
|
2948
|
+
#else
|
|
2011
2949
|
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, rbce->max_redirs);
|
|
2950
|
+
#endif
|
|
2012
2951
|
|
|
2013
2952
|
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, rbce->proxy_tunnel);
|
|
2014
2953
|
curl_easy_setopt(curl, CURLOPT_FILETIME, rbce->fetch_file_time);
|
|
@@ -2023,13 +2962,22 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2023
2962
|
|
|
2024
2963
|
curl_easy_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, rbce->unrestricted_auth);
|
|
2025
2964
|
|
|
2026
|
-
|
|
2965
|
+
#ifdef HAVE_CURLOPT_TIMEOUT_MS
|
|
2966
|
+
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, rbce->timeout_ms);
|
|
2967
|
+
#endif
|
|
2968
|
+
|
|
2027
2969
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, rbce->connect_timeout);
|
|
2970
|
+
#ifdef HAVE_CURLOPT_CONNECTTIMEOUT_MS
|
|
2971
|
+
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT_MS, rbce->connect_timeout_ms);
|
|
2972
|
+
#endif
|
|
2028
2973
|
curl_easy_setopt(curl, CURLOPT_DNS_CACHE_TIMEOUT, rbce->dns_cache_timeout);
|
|
2029
2974
|
|
|
2030
2975
|
curl_easy_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, rbce->ignore_content_length);
|
|
2031
2976
|
|
|
2032
2977
|
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, rbce->resolve_mode);
|
|
2978
|
+
#if HAVE_CURLOPT_HTTP_VERSION
|
|
2979
|
+
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, rbce->http_version);
|
|
2980
|
+
#endif
|
|
2033
2981
|
|
|
2034
2982
|
|
|
2035
2983
|
#if LIBCURL_VERSION_NUM >= 0x070a08
|
|
@@ -2043,6 +2991,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2043
2991
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, rbce->low_speed_limit);
|
|
2044
2992
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, rbce->low_speed_time);
|
|
2045
2993
|
|
|
2994
|
+
curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, rbce->max_recv_speed_large);
|
|
2995
|
+
curl_easy_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, rbce->max_send_speed_large);
|
|
2996
|
+
|
|
2046
2997
|
// Set up localport / proxy port
|
|
2047
2998
|
// FIXME these won't get returned to default if they're unset Ruby
|
|
2048
2999
|
if (rbce->proxy_port > 0) {
|
|
@@ -2075,29 +3026,27 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2075
3026
|
#endif
|
|
2076
3027
|
}
|
|
2077
3028
|
|
|
2078
|
-
|
|
3029
|
+
/*
|
|
3030
|
+
* NOTE: we used to set CURLAUTH_ANY but see: http://curl.haxx.se/mail/lib-2015-06/0033.html
|
|
3031
|
+
*/
|
|
3032
|
+
if (rbce->http_auth_types != 0) {
|
|
2079
3033
|
#if LIBCURL_VERSION_NUM >= 0x070a06
|
|
2080
3034
|
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, rbce->http_auth_types);
|
|
2081
|
-
} else {
|
|
2082
|
-
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
|
|
2083
3035
|
#else
|
|
2084
3036
|
rb_warn("Installed libcurl is too old to support http_auth_types");
|
|
2085
3037
|
#endif
|
|
2086
3038
|
}
|
|
2087
3039
|
|
|
2088
|
-
if (rbce->proxy_auth_types
|
|
3040
|
+
if (rbce->proxy_auth_types != 0) {
|
|
2089
3041
|
#if LIBCURL_VERSION_NUM >= 0x070a07
|
|
2090
3042
|
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, rbce->proxy_auth_types);
|
|
2091
|
-
} else {
|
|
2092
|
-
curl_easy_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
|
|
2093
3043
|
#else
|
|
2094
3044
|
rb_warn("Installed libcurl is too old to support proxy_auth_types");
|
|
2095
3045
|
#endif
|
|
2096
3046
|
}
|
|
2097
3047
|
|
|
2098
|
-
/* Set up HTTP cookie handling if necessary
|
|
2099
|
-
|
|
2100
|
-
*/
|
|
3048
|
+
/* Set up HTTP cookie handling if necessary */
|
|
3049
|
+
/* Enable/attach cookie engine if requested, or implicitly via COOKIELIST usage */
|
|
2101
3050
|
if (rbce->enable_cookies) {
|
|
2102
3051
|
if (!rb_easy_nil("cookiejar")) {
|
|
2103
3052
|
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, rb_easy_get_str("cookiejar"));
|
|
@@ -2108,6 +3057,9 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2108
3057
|
} else {
|
|
2109
3058
|
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, ""); /* "" = magic to just enable */
|
|
2110
3059
|
}
|
|
3060
|
+
} else if (rbce->cookielist_engine_enabled) {
|
|
3061
|
+
/* Ensure cookie engine is enabled even if enable_cookies? is false. */
|
|
3062
|
+
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
|
|
2111
3063
|
}
|
|
2112
3064
|
|
|
2113
3065
|
if (!rb_easy_nil("cookies")) {
|
|
@@ -2150,7 +3102,7 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2150
3102
|
rb_warn("libcurl is not configured with SSL support");
|
|
2151
3103
|
}
|
|
2152
3104
|
#endif
|
|
2153
|
-
|
|
3105
|
+
|
|
2154
3106
|
if (rbce->ftp_filemethod > 0) {
|
|
2155
3107
|
curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, rbce->ftp_filemethod);
|
|
2156
3108
|
}
|
|
@@ -2165,11 +3117,15 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2165
3117
|
|
|
2166
3118
|
if (!rb_easy_nil("headers")) {
|
|
2167
3119
|
if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_HASH)) {
|
|
2168
|
-
VALUE wrap =
|
|
2169
|
-
|
|
3120
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, hdrs);
|
|
3121
|
+
rb_block_call(rb_easy_get("headers"), rb_intern("each"), 0, NULL, cb_each_http_header, wrap);
|
|
2170
3122
|
} else {
|
|
2171
3123
|
VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
|
|
2172
|
-
*
|
|
3124
|
+
struct curl_slist *new_list = curl_slist_append(*hdrs, StringValuePtr(headers_str));
|
|
3125
|
+
if (!new_list) {
|
|
3126
|
+
rb_raise(rb_eNoMemError, "Failed to append to headers list");
|
|
3127
|
+
}
|
|
3128
|
+
*hdrs = new_list;
|
|
2173
3129
|
}
|
|
2174
3130
|
|
|
2175
3131
|
if (*hdrs) {
|
|
@@ -2177,11 +3133,34 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2177
3133
|
}
|
|
2178
3134
|
}
|
|
2179
3135
|
|
|
3136
|
+
#ifdef HAVE_CURLOPT_PROXYHEADER
|
|
3137
|
+
/* Setup HTTP proxy headers if necessary */
|
|
3138
|
+
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, NULL); // XXX: maybe we shouldn't be clearing this?
|
|
3139
|
+
|
|
3140
|
+
if (!rb_easy_nil("proxy_headers")) {
|
|
3141
|
+
if (rb_easy_type_check("proxy_headers", T_ARRAY) || rb_easy_type_check("proxy_headers", T_HASH)) {
|
|
3142
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, phdrs);
|
|
3143
|
+
rb_block_call(rb_easy_get("proxy_headers"), rb_intern("each"), 0, NULL, cb_each_http_proxy_header, wrap);
|
|
3144
|
+
} else {
|
|
3145
|
+
VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
|
|
3146
|
+
struct curl_slist *new_list = curl_slist_append(*phdrs, StringValuePtr(proxy_headers_str));
|
|
3147
|
+
if (!new_list) {
|
|
3148
|
+
rb_raise(rb_eNoMemError, "Failed to append to proxy headers list");
|
|
3149
|
+
}
|
|
3150
|
+
*phdrs = new_list;
|
|
3151
|
+
}
|
|
3152
|
+
|
|
3153
|
+
if (*phdrs) {
|
|
3154
|
+
curl_easy_setopt(curl, CURLOPT_PROXYHEADER, *phdrs);
|
|
3155
|
+
}
|
|
3156
|
+
}
|
|
3157
|
+
#endif
|
|
3158
|
+
|
|
2180
3159
|
/* Setup FTP commands if necessary */
|
|
2181
3160
|
if (!rb_easy_nil("ftp_commands")) {
|
|
2182
3161
|
if (rb_easy_type_check("ftp_commands", T_ARRAY)) {
|
|
2183
|
-
VALUE wrap =
|
|
2184
|
-
|
|
3162
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, cmds);
|
|
3163
|
+
rb_block_call(rb_easy_get("ftp_commands"), rb_intern("each"), 0, NULL, cb_each_ftp_command, wrap);
|
|
2185
3164
|
}
|
|
2186
3165
|
|
|
2187
3166
|
if (*cmds) {
|
|
@@ -2189,38 +3168,108 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
2189
3168
|
}
|
|
2190
3169
|
}
|
|
2191
3170
|
|
|
3171
|
+
#ifdef HAVE_CURLOPT_RESOLVE
|
|
3172
|
+
/* Setup resolve list if necessary */
|
|
3173
|
+
if (!rb_easy_nil("resolve")) {
|
|
3174
|
+
if (rb_easy_type_check("resolve", T_ARRAY)) {
|
|
3175
|
+
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, rslv);
|
|
3176
|
+
rb_block_call(rb_easy_get("resolve"), rb_intern("each"), 0, NULL, cb_each_resolve, wrap);
|
|
3177
|
+
} else {
|
|
3178
|
+
VALUE resolve_str = rb_obj_as_string(rb_easy_get("resolve"));
|
|
3179
|
+
struct curl_slist *new_list = curl_slist_append(*rslv, StringValuePtr(resolve_str));
|
|
3180
|
+
if (!new_list) {
|
|
3181
|
+
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
3182
|
+
}
|
|
3183
|
+
*rslv = new_list;
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
if (*rslv) {
|
|
3187
|
+
curl_easy_setopt(curl, CURLOPT_RESOLVE, *rslv);
|
|
3188
|
+
}
|
|
3189
|
+
}
|
|
3190
|
+
#endif
|
|
3191
|
+
|
|
2192
3192
|
return Qnil;
|
|
2193
3193
|
}
|
|
2194
3194
|
/***********************************************
|
|
2195
3195
|
*
|
|
2196
3196
|
* Clean up a connection
|
|
2197
3197
|
*
|
|
2198
|
-
* Always returns
|
|
3198
|
+
* Always returns Qnil.
|
|
2199
3199
|
*/
|
|
2200
3200
|
VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2201
3201
|
|
|
2202
3202
|
CURL *curl = rbce->curl;
|
|
2203
3203
|
struct curl_slist *ftp_commands;
|
|
3204
|
+
struct curl_slist *resolve;
|
|
3205
|
+
|
|
3206
|
+
ruby_curl_easy_clear_headers_list(rbce);
|
|
3207
|
+
ruby_curl_easy_clear_proxy_headers_list(rbce);
|
|
2204
3208
|
|
|
2205
|
-
|
|
2206
|
-
if (
|
|
2207
|
-
|
|
2208
|
-
|
|
3209
|
+
ftp_commands = rbce->curl_ftp_commands;
|
|
3210
|
+
if (ftp_commands) {
|
|
3211
|
+
ruby_curl_easy_clear_ftp_commands_list(rbce);
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
resolve = rbce->curl_resolve;
|
|
3215
|
+
if (resolve) {
|
|
3216
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
3217
|
+
}
|
|
3218
|
+
|
|
3219
|
+
/* clean up a PUT request's curl options. */
|
|
3220
|
+
if (!rb_easy_nil("upload")) {
|
|
3221
|
+
rb_easy_del("upload"); // set the upload object to Qnil to let the GC clean up
|
|
3222
|
+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
|
3223
|
+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
|
3224
|
+
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
|
|
3225
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
3226
|
+
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, NULL);
|
|
3227
|
+
#endif
|
|
3228
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
3229
|
+
curl_easy_setopt(curl, CURLOPT_SEEKDATA, NULL);
|
|
3230
|
+
#endif
|
|
3231
|
+
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
|
2209
3232
|
}
|
|
2210
3233
|
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
3234
|
+
// set values on cleanup to nil
|
|
3235
|
+
//rb_easy_del("multi");
|
|
3236
|
+
|
|
3237
|
+
return Qnil;
|
|
3238
|
+
}
|
|
3239
|
+
|
|
3240
|
+
struct easy_perform_request_restore_args {
|
|
3241
|
+
VALUE self;
|
|
3242
|
+
CURL *curl;
|
|
3243
|
+
ruby_curl_easy *rbce;
|
|
3244
|
+
int clear_customrequest;
|
|
3245
|
+
int clear_nobody;
|
|
3246
|
+
int clear_postfields;
|
|
3247
|
+
};
|
|
3248
|
+
|
|
3249
|
+
static VALUE perform_with_request_restore_body(VALUE argp) {
|
|
3250
|
+
struct easy_perform_request_restore_args *args = (struct easy_perform_request_restore_args *)argp;
|
|
3251
|
+
return rb_funcall(args->self, rb_intern("perform"), 0);
|
|
3252
|
+
}
|
|
3253
|
+
|
|
3254
|
+
static VALUE perform_with_request_restore_ensure(VALUE argp) {
|
|
3255
|
+
struct easy_perform_request_restore_args *args = (struct easy_perform_request_restore_args *)argp;
|
|
2216
3256
|
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
3257
|
+
if (args->curl) {
|
|
3258
|
+
if (args->clear_nobody) {
|
|
3259
|
+
curl_easy_setopt(args->curl, CURLOPT_NOBODY, 0L);
|
|
3260
|
+
}
|
|
3261
|
+
if (args->clear_customrequest) {
|
|
3262
|
+
curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
3263
|
+
}
|
|
3264
|
+
if (args->clear_postfields) {
|
|
3265
|
+
curl_easy_setopt(args->curl, CURLOPT_POST, 0L);
|
|
3266
|
+
curl_easy_setopt(args->curl, CURLOPT_POSTFIELDS, NULL);
|
|
3267
|
+
curl_easy_setopt(args->curl, CURLOPT_POSTFIELDSIZE, 0L);
|
|
3268
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPGET, 1L);
|
|
3269
|
+
if (args->rbce && !NIL_P(args->rbce->opts)) {
|
|
3270
|
+
rb_hash_delete(args->rbce->opts, rb_easy_hkey("postdata_buffer"));
|
|
3271
|
+
}
|
|
3272
|
+
}
|
|
2224
3273
|
}
|
|
2225
3274
|
|
|
2226
3275
|
return Qnil;
|
|
@@ -2234,14 +3283,33 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
|
2234
3283
|
CURL *curl;
|
|
2235
3284
|
VALUE retval;
|
|
2236
3285
|
|
|
2237
|
-
|
|
3286
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2238
3287
|
curl = rbce->curl;
|
|
2239
3288
|
|
|
3289
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
3290
|
+
|
|
3291
|
+
/* Use method override and adjust related options for special verbs. */
|
|
2240
3292
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
|
2241
3293
|
|
|
2242
|
-
|
|
3294
|
+
/* For HEAD, ensure no body is requested/downloaded, as some servers
|
|
3295
|
+
* include a Content-Length header which should not cause libcurl to
|
|
3296
|
+
* wait for a body that will never arrive. */
|
|
3297
|
+
int is_head = (verb && (
|
|
3298
|
+
#ifdef _WIN32
|
|
3299
|
+
_stricmp(verb, "HEAD") == 0
|
|
3300
|
+
#else
|
|
3301
|
+
strcasecmp(verb, "HEAD") == 0
|
|
3302
|
+
#endif
|
|
3303
|
+
));
|
|
3304
|
+
if (is_head) {
|
|
3305
|
+
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
|
|
3306
|
+
curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
|
|
3307
|
+
curl_easy_setopt(curl, CURLOPT_POST, 0L);
|
|
3308
|
+
}
|
|
2243
3309
|
|
|
2244
|
-
|
|
3310
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, is_head, 0 };
|
|
3311
|
+
retval = rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
3312
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
2245
3313
|
|
|
2246
3314
|
return retval;
|
|
2247
3315
|
}
|
|
@@ -2267,6 +3335,76 @@ static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
|
|
|
2267
3335
|
}
|
|
2268
3336
|
}
|
|
2269
3337
|
|
|
3338
|
+
static VALUE call_easy_perform(VALUE self) {
|
|
3339
|
+
return rb_funcall(self, rb_intern("perform"), 0);
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
struct easy_form_perform_args {
|
|
3343
|
+
VALUE self;
|
|
3344
|
+
CURL *curl;
|
|
3345
|
+
int argc;
|
|
3346
|
+
VALUE *argv;
|
|
3347
|
+
struct curl_httppost *first;
|
|
3348
|
+
struct curl_httppost *last;
|
|
3349
|
+
int clear_customrequest;
|
|
3350
|
+
int form_set_on_curl;
|
|
3351
|
+
};
|
|
3352
|
+
|
|
3353
|
+
static void append_multipart_form_argument(VALUE arg,
|
|
3354
|
+
struct curl_httppost **first,
|
|
3355
|
+
struct curl_httppost **last) {
|
|
3356
|
+
if (rb_obj_is_instance_of(arg, cCurlPostField)) {
|
|
3357
|
+
append_to_form(arg, first, last);
|
|
3358
|
+
} else if (rb_type(arg) == T_ARRAY) {
|
|
3359
|
+
long j, argv_len = RARRAY_LEN(arg);
|
|
3360
|
+
for (j = 0; j < argv_len; ++j) {
|
|
3361
|
+
VALUE field = rb_ary_entry(arg, j);
|
|
3362
|
+
if (rb_obj_is_instance_of(field, cCurlPostField)) {
|
|
3363
|
+
append_to_form(field, first, last);
|
|
3364
|
+
} else {
|
|
3365
|
+
rb_raise(eCurlErrInvalidPostField,
|
|
3366
|
+
"You must use PostFields only with multipart form posts");
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
} else {
|
|
3370
|
+
rb_raise(eCurlErrInvalidPostField,
|
|
3371
|
+
"You must use PostFields only with multipart form posts");
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
static VALUE build_and_perform_multipart_form(VALUE argp) {
|
|
3376
|
+
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
3377
|
+
int i;
|
|
3378
|
+
|
|
3379
|
+
for (i = 0; i < args->argc; i++) {
|
|
3380
|
+
append_multipart_form_argument(args->argv[i], &args->first, &args->last);
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
curl_easy_setopt(args->curl, CURLOPT_POST, 0);
|
|
3384
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, args->first);
|
|
3385
|
+
args->form_set_on_curl = 1;
|
|
3386
|
+
|
|
3387
|
+
return call_easy_perform(args->self);
|
|
3388
|
+
}
|
|
3389
|
+
|
|
3390
|
+
static VALUE ensure_free_form_post(VALUE argp) {
|
|
3391
|
+
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
3392
|
+
if (args->curl) {
|
|
3393
|
+
if (args->form_set_on_curl) {
|
|
3394
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, NULL);
|
|
3395
|
+
}
|
|
3396
|
+
if (args->clear_customrequest) {
|
|
3397
|
+
curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
if (args->first) {
|
|
3401
|
+
curl_formfree(args->first);
|
|
3402
|
+
args->first = NULL;
|
|
3403
|
+
}
|
|
3404
|
+
args->last = NULL;
|
|
3405
|
+
return Qnil;
|
|
3406
|
+
}
|
|
3407
|
+
|
|
2270
3408
|
/*
|
|
2271
3409
|
* call-seq:
|
|
2272
3410
|
* easy.http_post("url=encoded%20form%20data;and=so%20on") => true
|
|
@@ -2294,45 +3432,21 @@ static VALUE ruby_curl_easy_perform_verb(VALUE self, VALUE verb) {
|
|
|
2294
3432
|
static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2295
3433
|
ruby_curl_easy *rbce;
|
|
2296
3434
|
CURL *curl;
|
|
2297
|
-
int i;
|
|
2298
3435
|
VALUE args_ary;
|
|
2299
3436
|
|
|
2300
3437
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
2301
3438
|
|
|
2302
|
-
|
|
3439
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2303
3440
|
curl = rbce->curl;
|
|
2304
3441
|
|
|
3442
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
3443
|
+
|
|
2305
3444
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
2306
3445
|
|
|
2307
3446
|
if (rbce->multipart_form_post) {
|
|
2308
3447
|
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);
|
|
3448
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0 };
|
|
3449
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
2336
3450
|
|
|
2337
3451
|
return ret;
|
|
2338
3452
|
} else {
|
|
@@ -2353,7 +3467,65 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
2353
3467
|
ruby_curl_easy_post_body_set(self, post_body);
|
|
2354
3468
|
}
|
|
2355
3469
|
|
|
2356
|
-
|
|
3470
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, 0, 0 };
|
|
3471
|
+
return rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
3472
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
/*
|
|
3478
|
+
* call-seq:
|
|
3479
|
+
* easy.http_patch("url=encoded%20form%20data;and=so%20on") => true
|
|
3480
|
+
* easy.http_patch("url=encoded%20form%20data", "and=so%20on", ...) => true
|
|
3481
|
+
* easy.http_patch("url=encoded%20form%20data", Curl::PostField, "and=so%20on", ...) => true
|
|
3482
|
+
* easy.http_patch(Curl::PostField, Curl::PostField ..., Curl::PostField) => true
|
|
3483
|
+
*
|
|
3484
|
+
* PATCH the specified formdata to the currently configured URL using
|
|
3485
|
+
* the current options set for this Curl::Easy instance. This method
|
|
3486
|
+
* always returns true, or raises an exception (defined under
|
|
3487
|
+
* Curl::Err) on error.
|
|
3488
|
+
*
|
|
3489
|
+
* When multipart_form_post is true the multipart logic is used; otherwise,
|
|
3490
|
+
* the arguments are joined into a raw PATCH body.
|
|
3491
|
+
*/
|
|
3492
|
+
static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
3493
|
+
ruby_curl_easy *rbce;
|
|
3494
|
+
CURL *curl;
|
|
3495
|
+
VALUE args_ary;
|
|
3496
|
+
|
|
3497
|
+
rb_scan_args(argc, argv, "*", &args_ary);
|
|
3498
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3499
|
+
curl = rbce->curl;
|
|
3500
|
+
|
|
3501
|
+
/* Clear the error buffer */
|
|
3502
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
3503
|
+
|
|
3504
|
+
/* Set the custom HTTP method to PATCH */
|
|
3505
|
+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
|
|
3506
|
+
|
|
3507
|
+
if (rbce->multipart_form_post) {
|
|
3508
|
+
VALUE ret;
|
|
3509
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
3510
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
3511
|
+
return ret;
|
|
3512
|
+
} else {
|
|
3513
|
+
/* Join arguments into a raw PATCH body */
|
|
3514
|
+
VALUE patch_body = rb_funcall(args_ary, idJoin, 1, rbstrAmp);
|
|
3515
|
+
if (patch_body == Qnil) {
|
|
3516
|
+
rb_raise(eCurlErrError, "Failed to join arguments");
|
|
3517
|
+
return Qnil;
|
|
3518
|
+
} else {
|
|
3519
|
+
if (rb_type(patch_body) == T_STRING && RSTRING_LEN(patch_body) > 0) {
|
|
3520
|
+
ruby_curl_easy_post_body_set(self, patch_body);
|
|
3521
|
+
}
|
|
3522
|
+
/* If postdata_buffer is still nil, set it so that the PATCH header is enabled */
|
|
3523
|
+
if (rb_easy_nil("postdata_buffer")) {
|
|
3524
|
+
ruby_curl_easy_post_body_set(self, patch_body);
|
|
3525
|
+
}
|
|
3526
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, 0, 1 };
|
|
3527
|
+
return rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
3528
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
2357
3529
|
}
|
|
2358
3530
|
}
|
|
2359
3531
|
}
|
|
@@ -2366,17 +3538,47 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
2366
3538
|
* current options set for this Curl::Easy instance. This method always
|
|
2367
3539
|
* returns true, or raises an exception (defined under Curl::Err) on error.
|
|
2368
3540
|
*/
|
|
2369
|
-
static VALUE ruby_curl_easy_perform_put(VALUE
|
|
3541
|
+
static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
2370
3542
|
ruby_curl_easy *rbce;
|
|
2371
3543
|
CURL *curl;
|
|
3544
|
+
VALUE args_ary;
|
|
2372
3545
|
|
|
2373
|
-
|
|
3546
|
+
rb_scan_args(argc, argv, "*", &args_ary);
|
|
3547
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2374
3548
|
curl = rbce->curl;
|
|
2375
3549
|
|
|
2376
|
-
|
|
2377
|
-
|
|
3550
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
|
3551
|
+
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
|
|
2378
3552
|
|
|
2379
|
-
|
|
3553
|
+
/* New: if no arguments were provided, treat as an empty PUT */
|
|
3554
|
+
if (RARRAY_LEN(args_ary) == 0) {
|
|
3555
|
+
/* Option 1: explicitly set an empty body */
|
|
3556
|
+
ruby_curl_easy_put_data_set(self, rb_str_new2(""));
|
|
3557
|
+
}
|
|
3558
|
+
/* If a single argument is given and it is a String or responds to read, use legacy behavior */
|
|
3559
|
+
else if (RARRAY_LEN(args_ary) == 1 &&
|
|
3560
|
+
(rb_type(rb_ary_entry(args_ary, 0)) == T_STRING ||
|
|
3561
|
+
rb_respond_to(rb_ary_entry(args_ary, 0), rb_intern("read")))) {
|
|
3562
|
+
ruby_curl_easy_put_data_set(self, rb_ary_entry(args_ary, 0));
|
|
3563
|
+
}
|
|
3564
|
+
/* Otherwise, if multipart_form_post is true, use multipart logic */
|
|
3565
|
+
else if (rbce->multipart_form_post) {
|
|
3566
|
+
VALUE ret;
|
|
3567
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
3568
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
3569
|
+
return ret;
|
|
3570
|
+
}
|
|
3571
|
+
/* Fallback: join all arguments */
|
|
3572
|
+
else {
|
|
3573
|
+
VALUE post_body = rb_funcall(args_ary, idJoin, 1, rbstrAmp);
|
|
3574
|
+
if (post_body != Qnil && rb_type(post_body) == T_STRING &&
|
|
3575
|
+
RSTRING_LEN(post_body) > 0) {
|
|
3576
|
+
ruby_curl_easy_put_data_set(self, post_body);
|
|
3577
|
+
}
|
|
3578
|
+
}
|
|
3579
|
+
struct easy_perform_request_restore_args restore_args = { self, curl, rbce, 1, 0, 0 };
|
|
3580
|
+
return rb_ensure(perform_with_request_restore_body, (VALUE)&restore_args,
|
|
3581
|
+
perform_with_request_restore_ensure, (VALUE)&restore_args);
|
|
2380
3582
|
}
|
|
2381
3583
|
|
|
2382
3584
|
|
|
@@ -2391,6 +3593,10 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
|
2391
3593
|
* your own body handler, this string will be empty.
|
|
2392
3594
|
*/
|
|
2393
3595
|
static VALUE ruby_curl_easy_body_str_get(VALUE self) {
|
|
3596
|
+
/*
|
|
3597
|
+
TODO: can we force_encoding on the return here if we see charset=utf-8 in the content-type header?
|
|
3598
|
+
Content-Type: application/json; charset=utf-8
|
|
3599
|
+
*/
|
|
2394
3600
|
CURB_OBJECT_HGETTER(ruby_curl_easy, body_data);
|
|
2395
3601
|
}
|
|
2396
3602
|
|
|
@@ -2421,7 +3627,7 @@ static VALUE ruby_curl_easy_last_effective_url_get(VALUE self) {
|
|
|
2421
3627
|
ruby_curl_easy *rbce;
|
|
2422
3628
|
char* url;
|
|
2423
3629
|
|
|
2424
|
-
|
|
3630
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2425
3631
|
curl_easy_getinfo(rbce->curl, CURLINFO_EFFECTIVE_URL, &url);
|
|
2426
3632
|
|
|
2427
3633
|
if (url && url[0]) { // curl returns empty string if none
|
|
@@ -2444,7 +3650,7 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
|
2444
3650
|
ruby_curl_easy *rbce;
|
|
2445
3651
|
long code;
|
|
2446
3652
|
|
|
2447
|
-
|
|
3653
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2448
3654
|
#ifdef HAVE_CURLINFO_RESPONSE_CODE
|
|
2449
3655
|
curl_easy_getinfo(rbce->curl, CURLINFO_RESPONSE_CODE, &code);
|
|
2450
3656
|
#else
|
|
@@ -2467,8 +3673,8 @@ static VALUE ruby_curl_easy_response_code_get(VALUE self) {
|
|
|
2467
3673
|
static VALUE ruby_curl_easy_primary_ip_get(VALUE self) {
|
|
2468
3674
|
ruby_curl_easy *rbce;
|
|
2469
3675
|
char* ip;
|
|
2470
|
-
|
|
2471
|
-
|
|
3676
|
+
|
|
3677
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2472
3678
|
curl_easy_getinfo(rbce->curl, CURLINFO_PRIMARY_IP, &ip);
|
|
2473
3679
|
|
|
2474
3680
|
if (ip && ip[0]) { // curl returns empty string if none
|
|
@@ -2489,7 +3695,7 @@ static VALUE ruby_curl_easy_http_connect_code_get(VALUE self) {
|
|
|
2489
3695
|
ruby_curl_easy *rbce;
|
|
2490
3696
|
long code;
|
|
2491
3697
|
|
|
2492
|
-
|
|
3698
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2493
3699
|
curl_easy_getinfo(rbce->curl, CURLINFO_HTTP_CONNECTCODE, &code);
|
|
2494
3700
|
|
|
2495
3701
|
return LONG2NUM(code);
|
|
@@ -2517,13 +3723,13 @@ static VALUE ruby_curl_easy_file_time_get(VALUE self) {
|
|
|
2517
3723
|
ruby_curl_easy *rbce;
|
|
2518
3724
|
long time;
|
|
2519
3725
|
|
|
2520
|
-
|
|
3726
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2521
3727
|
curl_easy_getinfo(rbce->curl, CURLINFO_FILETIME, &time);
|
|
2522
3728
|
|
|
2523
3729
|
return LONG2NUM(time);
|
|
2524
3730
|
#else
|
|
2525
3731
|
rb_warn("Installed libcurl is too old to support file_time");
|
|
2526
|
-
return
|
|
3732
|
+
return LONG2NUM(0);
|
|
2527
3733
|
#endif
|
|
2528
3734
|
}
|
|
2529
3735
|
|
|
@@ -2538,7 +3744,7 @@ static VALUE ruby_curl_easy_total_time_get(VALUE self) {
|
|
|
2538
3744
|
ruby_curl_easy *rbce;
|
|
2539
3745
|
double time;
|
|
2540
3746
|
|
|
2541
|
-
|
|
3747
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2542
3748
|
curl_easy_getinfo(rbce->curl, CURLINFO_TOTAL_TIME, &time);
|
|
2543
3749
|
|
|
2544
3750
|
return rb_float_new(time);
|
|
@@ -2555,7 +3761,7 @@ static VALUE ruby_curl_easy_name_lookup_time_get(VALUE self) {
|
|
|
2555
3761
|
ruby_curl_easy *rbce;
|
|
2556
3762
|
double time;
|
|
2557
3763
|
|
|
2558
|
-
|
|
3764
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2559
3765
|
curl_easy_getinfo(rbce->curl, CURLINFO_NAMELOOKUP_TIME, &time);
|
|
2560
3766
|
|
|
2561
3767
|
return rb_float_new(time);
|
|
@@ -2572,12 +3778,35 @@ static VALUE ruby_curl_easy_connect_time_get(VALUE self) {
|
|
|
2572
3778
|
ruby_curl_easy *rbce;
|
|
2573
3779
|
double time;
|
|
2574
3780
|
|
|
2575
|
-
|
|
3781
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2576
3782
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONNECT_TIME, &time);
|
|
2577
3783
|
|
|
2578
3784
|
return rb_float_new(time);
|
|
2579
3785
|
}
|
|
2580
3786
|
|
|
3787
|
+
/*
|
|
3788
|
+
* call-seq:
|
|
3789
|
+
* easy.app_connect_time => float
|
|
3790
|
+
*
|
|
3791
|
+
* Retrieve the time, in seconds, it took from the start until the SSL/SSH
|
|
3792
|
+
* connect/handshake to the remote host was completed. This time is most often
|
|
3793
|
+
* very near to the pre transfer time, except for cases such as HTTP
|
|
3794
|
+
* pipelining where the pretransfer time can be delayed due to waits in line
|
|
3795
|
+
* for the pipeline and more.
|
|
3796
|
+
*/
|
|
3797
|
+
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
|
3798
|
+
static VALUE ruby_curl_easy_app_connect_time_get(VALUE self) {
|
|
3799
|
+
ruby_curl_easy *rbce;
|
|
3800
|
+
double time;
|
|
3801
|
+
|
|
3802
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3803
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_APPCONNECT_TIME, &time);
|
|
3804
|
+
|
|
3805
|
+
return rb_float_new(time);
|
|
3806
|
+
}
|
|
3807
|
+
#endif
|
|
3808
|
+
|
|
3809
|
+
|
|
2581
3810
|
/*
|
|
2582
3811
|
* call-seq:
|
|
2583
3812
|
* easy.pre_transfer_time => float
|
|
@@ -2591,7 +3820,7 @@ static VALUE ruby_curl_easy_pre_transfer_time_get(VALUE self) {
|
|
|
2591
3820
|
ruby_curl_easy *rbce;
|
|
2592
3821
|
double time;
|
|
2593
3822
|
|
|
2594
|
-
|
|
3823
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2595
3824
|
curl_easy_getinfo(rbce->curl, CURLINFO_PRETRANSFER_TIME, &time);
|
|
2596
3825
|
|
|
2597
3826
|
return rb_float_new(time);
|
|
@@ -2609,7 +3838,7 @@ static VALUE ruby_curl_easy_start_transfer_time_get(VALUE self) {
|
|
|
2609
3838
|
ruby_curl_easy *rbce;
|
|
2610
3839
|
double time;
|
|
2611
3840
|
|
|
2612
|
-
|
|
3841
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2613
3842
|
curl_easy_getinfo(rbce->curl, CURLINFO_STARTTRANSFER_TIME, &time);
|
|
2614
3843
|
|
|
2615
3844
|
return rb_float_new(time);
|
|
@@ -2631,7 +3860,7 @@ static VALUE ruby_curl_easy_redirect_time_get(VALUE self) {
|
|
|
2631
3860
|
ruby_curl_easy *rbce;
|
|
2632
3861
|
double time;
|
|
2633
3862
|
|
|
2634
|
-
|
|
3863
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2635
3864
|
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_TIME, &time);
|
|
2636
3865
|
|
|
2637
3866
|
return rb_float_new(time);
|
|
@@ -2654,13 +3883,13 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
|
2654
3883
|
ruby_curl_easy *rbce;
|
|
2655
3884
|
long count;
|
|
2656
3885
|
|
|
2657
|
-
|
|
3886
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2658
3887
|
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_COUNT, &count);
|
|
2659
3888
|
|
|
2660
3889
|
return LONG2NUM(count);
|
|
2661
3890
|
#else
|
|
2662
3891
|
rb_warn("Installed libcurl is too old to support redirect_count");
|
|
2663
|
-
return
|
|
3892
|
+
return LONG2NUM(-1);
|
|
2664
3893
|
#endif
|
|
2665
3894
|
|
|
2666
3895
|
}
|
|
@@ -2669,7 +3898,7 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
|
2669
3898
|
* call-seq:
|
|
2670
3899
|
* easy.redirect_url => "http://some.url" or nil
|
|
2671
3900
|
*
|
|
2672
|
-
* Retrieve the URL a redirect would take you to if you
|
|
3901
|
+
* Retrieve the URL a redirect would take you to if you
|
|
2673
3902
|
* would enable CURLOPT_FOLLOWLOCATION.
|
|
2674
3903
|
*
|
|
2675
3904
|
* Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
|
|
@@ -2679,7 +3908,7 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
2679
3908
|
ruby_curl_easy *rbce;
|
|
2680
3909
|
char* url;
|
|
2681
3910
|
|
|
2682
|
-
|
|
3911
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2683
3912
|
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
|
|
2684
3913
|
|
|
2685
3914
|
if (url && url[0]) { // curl returns empty string if none
|
|
@@ -2689,7 +3918,7 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
2689
3918
|
}
|
|
2690
3919
|
#else
|
|
2691
3920
|
rb_warn("Installed libcurl is too old to support redirect_url");
|
|
2692
|
-
return
|
|
3921
|
+
return LONG2NUM(-1);
|
|
2693
3922
|
#endif
|
|
2694
3923
|
}
|
|
2695
3924
|
|
|
@@ -2704,12 +3933,17 @@ static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
|
|
2704
3933
|
*/
|
|
2705
3934
|
static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
|
|
2706
3935
|
ruby_curl_easy *rbce;
|
|
2707
|
-
|
|
3936
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2708
3937
|
|
|
2709
|
-
|
|
3938
|
+
#ifdef HAVE_CURLINFO_SIZE_UPLOAD_T
|
|
3939
|
+
curl_off_t bytes;
|
|
3940
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD_T, &bytes);
|
|
3941
|
+
return LL2NUM(bytes);
|
|
3942
|
+
#else
|
|
3943
|
+
double bytes;
|
|
2710
3944
|
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_UPLOAD, &bytes);
|
|
2711
|
-
|
|
2712
3945
|
return rb_float_new(bytes);
|
|
3946
|
+
#endif
|
|
2713
3947
|
}
|
|
2714
3948
|
|
|
2715
3949
|
/*
|
|
@@ -2721,12 +3955,17 @@ static VALUE ruby_curl_easy_uploaded_bytes_get(VALUE self) {
|
|
|
2721
3955
|
*/
|
|
2722
3956
|
static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
|
|
2723
3957
|
ruby_curl_easy *rbce;
|
|
2724
|
-
|
|
3958
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2725
3959
|
|
|
2726
|
-
|
|
3960
|
+
#ifdef HAVE_CURLINFO_SIZE_DOWNLOAD_T
|
|
3961
|
+
curl_off_t bytes;
|
|
3962
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD_T, &bytes);
|
|
3963
|
+
return LL2NUM(bytes);
|
|
3964
|
+
#else
|
|
3965
|
+
double bytes;
|
|
2727
3966
|
curl_easy_getinfo(rbce->curl, CURLINFO_SIZE_DOWNLOAD, &bytes);
|
|
2728
|
-
|
|
2729
3967
|
return rb_float_new(bytes);
|
|
3968
|
+
#endif
|
|
2730
3969
|
}
|
|
2731
3970
|
|
|
2732
3971
|
/*
|
|
@@ -2738,12 +3977,17 @@ static VALUE ruby_curl_easy_downloaded_bytes_get(VALUE self) {
|
|
|
2738
3977
|
*/
|
|
2739
3978
|
static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
|
|
2740
3979
|
ruby_curl_easy *rbce;
|
|
2741
|
-
|
|
3980
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2742
3981
|
|
|
2743
|
-
|
|
3982
|
+
#ifdef HAVE_CURLINFO_SPEED_UPLOAD_T
|
|
3983
|
+
curl_off_t bytes;
|
|
3984
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD_T, &bytes);
|
|
3985
|
+
return LL2NUM(bytes);
|
|
3986
|
+
#else
|
|
3987
|
+
double bytes;
|
|
2744
3988
|
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_UPLOAD, &bytes);
|
|
2745
|
-
|
|
2746
3989
|
return rb_float_new(bytes);
|
|
3990
|
+
#endif
|
|
2747
3991
|
}
|
|
2748
3992
|
|
|
2749
3993
|
/*
|
|
@@ -2755,12 +3999,17 @@ static VALUE ruby_curl_easy_upload_speed_get(VALUE self) {
|
|
|
2755
3999
|
*/
|
|
2756
4000
|
static VALUE ruby_curl_easy_download_speed_get(VALUE self) {
|
|
2757
4001
|
ruby_curl_easy *rbce;
|
|
2758
|
-
|
|
4002
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2759
4003
|
|
|
2760
|
-
|
|
4004
|
+
#ifdef HAVE_CURLINFO_SPEED_DOWNLOAD_T
|
|
4005
|
+
curl_off_t bytes;
|
|
4006
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD_T, &bytes);
|
|
4007
|
+
return LL2NUM(bytes);
|
|
4008
|
+
#else
|
|
4009
|
+
double bytes;
|
|
2761
4010
|
curl_easy_getinfo(rbce->curl, CURLINFO_SPEED_DOWNLOAD, &bytes);
|
|
2762
|
-
|
|
2763
4011
|
return rb_float_new(bytes);
|
|
4012
|
+
#endif
|
|
2764
4013
|
}
|
|
2765
4014
|
|
|
2766
4015
|
/*
|
|
@@ -2774,7 +4023,7 @@ static VALUE ruby_curl_easy_header_size_get(VALUE self) {
|
|
|
2774
4023
|
ruby_curl_easy *rbce;
|
|
2775
4024
|
long size;
|
|
2776
4025
|
|
|
2777
|
-
|
|
4026
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2778
4027
|
curl_easy_getinfo(rbce->curl, CURLINFO_HEADER_SIZE, &size);
|
|
2779
4028
|
|
|
2780
4029
|
return LONG2NUM(size);
|
|
@@ -2792,7 +4041,7 @@ static VALUE ruby_curl_easy_request_size_get(VALUE self) {
|
|
|
2792
4041
|
ruby_curl_easy *rbce;
|
|
2793
4042
|
long size;
|
|
2794
4043
|
|
|
2795
|
-
|
|
4044
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2796
4045
|
curl_easy_getinfo(rbce->curl, CURLINFO_REQUEST_SIZE, &size);
|
|
2797
4046
|
|
|
2798
4047
|
return LONG2NUM(size);
|
|
@@ -2809,7 +4058,7 @@ static VALUE ruby_curl_easy_ssl_verify_result_get(VALUE self) {
|
|
|
2809
4058
|
ruby_curl_easy *rbce;
|
|
2810
4059
|
long result;
|
|
2811
4060
|
|
|
2812
|
-
|
|
4061
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2813
4062
|
curl_easy_getinfo(rbce->curl, CURLINFO_SSL_VERIFYRESULT, &result);
|
|
2814
4063
|
|
|
2815
4064
|
return LONG2NUM(result);
|
|
@@ -2832,12 +4081,17 @@ NOTE: you must call curl_slist_free_all(3) on the list pointer once you're done
|
|
|
2832
4081
|
*/
|
|
2833
4082
|
static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
|
|
2834
4083
|
ruby_curl_easy *rbce;
|
|
2835
|
-
|
|
4084
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2836
4085
|
|
|
2837
|
-
|
|
4086
|
+
#ifdef HAVE_CURLINFO_CONTENT_LENGTH_DOWNLOAD_T
|
|
4087
|
+
curl_off_t bytes;
|
|
4088
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &bytes);
|
|
4089
|
+
return LL2NUM(bytes);
|
|
4090
|
+
#else
|
|
4091
|
+
double bytes;
|
|
2838
4092
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &bytes);
|
|
2839
|
-
|
|
2840
4093
|
return rb_float_new(bytes);
|
|
4094
|
+
#endif
|
|
2841
4095
|
}
|
|
2842
4096
|
|
|
2843
4097
|
/*
|
|
@@ -2848,12 +4102,17 @@ static VALUE ruby_curl_easy_downloaded_content_length_get(VALUE self) {
|
|
|
2848
4102
|
*/
|
|
2849
4103
|
static VALUE ruby_curl_easy_uploaded_content_length_get(VALUE self) {
|
|
2850
4104
|
ruby_curl_easy *rbce;
|
|
2851
|
-
|
|
4105
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2852
4106
|
|
|
2853
|
-
|
|
4107
|
+
#ifdef HAVE_CURLINFO_CONTENT_LENGTH_UPLOAD_T
|
|
4108
|
+
curl_off_t bytes;
|
|
4109
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD_T, &bytes);
|
|
4110
|
+
return LL2NUM(bytes);
|
|
4111
|
+
#else
|
|
4112
|
+
double bytes;
|
|
2854
4113
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_LENGTH_UPLOAD, &bytes);
|
|
2855
|
-
|
|
2856
4114
|
return rb_float_new(bytes);
|
|
4115
|
+
#endif
|
|
2857
4116
|
}
|
|
2858
4117
|
|
|
2859
4118
|
/*
|
|
@@ -2869,7 +4128,7 @@ static VALUE ruby_curl_easy_content_type_get(VALUE self) {
|
|
|
2869
4128
|
ruby_curl_easy *rbce;
|
|
2870
4129
|
char* type;
|
|
2871
4130
|
|
|
2872
|
-
|
|
4131
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2873
4132
|
curl_easy_getinfo(rbce->curl, CURLINFO_CONTENT_TYPE, &type);
|
|
2874
4133
|
|
|
2875
4134
|
if (type && type[0]) { // curl returns empty string if none
|
|
@@ -2912,13 +4171,13 @@ static VALUE ruby_curl_easy_os_errno_get(VALUE self) {
|
|
|
2912
4171
|
ruby_curl_easy *rbce;
|
|
2913
4172
|
long result;
|
|
2914
4173
|
|
|
2915
|
-
|
|
4174
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2916
4175
|
curl_easy_getinfo(rbce->curl, CURLINFO_OS_ERRNO, &result);
|
|
2917
4176
|
|
|
2918
4177
|
return LONG2NUM(result);
|
|
2919
4178
|
#else
|
|
2920
4179
|
rb_warn("Installed libcurl is too old to support os_errno");
|
|
2921
|
-
return
|
|
4180
|
+
return LONG2NUM(0);
|
|
2922
4181
|
#endif
|
|
2923
4182
|
}
|
|
2924
4183
|
|
|
@@ -2941,23 +4200,59 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
|
|
|
2941
4200
|
ruby_curl_easy *rbce;
|
|
2942
4201
|
long result;
|
|
2943
4202
|
|
|
2944
|
-
|
|
4203
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2945
4204
|
curl_easy_getinfo(rbce->curl, CURLINFO_NUM_CONNECTS, &result);
|
|
2946
4205
|
|
|
2947
4206
|
return LONG2NUM(result);
|
|
2948
4207
|
#else
|
|
2949
4208
|
rb_warn("Installed libcurl is too old to support num_connects");
|
|
2950
|
-
return
|
|
4209
|
+
return LONG2NUM(-1);
|
|
2951
4210
|
#endif
|
|
2952
4211
|
}
|
|
2953
4212
|
|
|
2954
4213
|
|
|
2955
|
-
/*
|
|
4214
|
+
/*
|
|
4215
|
+
* call-seq:
|
|
4216
|
+
* easy.cookielist => cookielist
|
|
4217
|
+
*
|
|
4218
|
+
* Retrieves the cookies curl knows in an array of strings.
|
|
4219
|
+
* Returned strings are in Netscape cookiejar format or in Set-Cookie format.
|
|
4220
|
+
* Since 7.43.0 cookies in the Set-Cookie format without a domain name are not exported.
|
|
4221
|
+
*
|
|
4222
|
+
* To modify the cookie engine (add/replace/remove), use +easy.cookielist= string+
|
|
4223
|
+
* or +easy.set(:cookielist, string)+ with one of the following accepted inputs:
|
|
4224
|
+
* - A Set-Cookie style header string: "Set-Cookie: name=value; Domain=example.com; Path=/; Expires=..."
|
|
4225
|
+
* - One or more lines in Netscape cookie file format (tab-separated fields)
|
|
4226
|
+
* - Special commands: "ALL" (clear all), "SESS" (remove session cookies), "FLUSH" (write to jar), "RELOAD" (reload from file)
|
|
4227
|
+
*
|
|
4228
|
+
* @see https://curl.se/libcurl/c/CURLINFO_COOKIELIST.html option <code>CURLINFO_COOKIELIST</code> of
|
|
4229
|
+
* <code>curl_easy_getopt(3)</code> to see how libcurl behaves.
|
|
4230
|
+
* @note requires libcurl 7.14.1 or higher, otherwise +-1+ is always returned
|
|
4231
|
+
* @return [Array<String>, nil, -1] array of strings, or +nil+ if there are no cookies, or +-1+ if the libcurl version is too old
|
|
4232
|
+
*/
|
|
4233
|
+
static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
|
|
4234
|
+
#ifdef HAVE_CURLINFO_COOKIELIST
|
|
4235
|
+
ruby_curl_easy *rbce;
|
|
4236
|
+
struct curl_slist *cookies;
|
|
4237
|
+
struct curl_slist *cookie;
|
|
4238
|
+
VALUE rb_cookies;
|
|
4239
|
+
|
|
4240
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4241
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_COOKIELIST, &cookies);
|
|
4242
|
+
if (!cookies)
|
|
4243
|
+
return Qnil;
|
|
4244
|
+
rb_cookies = rb_ary_new();
|
|
4245
|
+
for (cookie = cookies; cookie; cookie = cookie->next)
|
|
4246
|
+
rb_ary_push(rb_cookies, rb_str_new2(cookie->data));
|
|
4247
|
+
curl_slist_free_all(cookies);
|
|
4248
|
+
return rb_cookies;
|
|
2956
4249
|
|
|
2957
|
-
|
|
4250
|
+
#else
|
|
4251
|
+
rb_warn("Installed libcurl is too old to support cookielist");
|
|
4252
|
+
return INT2FIX(-1);
|
|
4253
|
+
#endif
|
|
4254
|
+
}
|
|
2958
4255
|
|
|
2959
|
-
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)
|
|
2960
|
-
*/
|
|
2961
4256
|
|
|
2962
4257
|
/* TODO this needs to be implemented. Could probably support CONNECT_ONLY by having this
|
|
2963
4258
|
* return an open Socket or something.
|
|
@@ -2982,7 +4277,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
2982
4277
|
ruby_curl_easy *rbce;
|
|
2983
4278
|
char* path = NULL;
|
|
2984
4279
|
|
|
2985
|
-
|
|
4280
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
2986
4281
|
curl_easy_getinfo(rbce->curl, CURLINFO_FTP_ENTRY_PATH, &path);
|
|
2987
4282
|
|
|
2988
4283
|
if (path && path[0]) { // curl returns NULL or empty string if none
|
|
@@ -2991,7 +4286,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
2991
4286
|
return Qnil;
|
|
2992
4287
|
}
|
|
2993
4288
|
#else
|
|
2994
|
-
rb_warn("Installed libcurl is too old to support
|
|
4289
|
+
rb_warn("Installed libcurl is too old to support ftp_entry_path");
|
|
2995
4290
|
return Qnil;
|
|
2996
4291
|
#endif
|
|
2997
4292
|
}
|
|
@@ -3002,7 +4297,7 @@ static VALUE ruby_curl_easy_ftp_entry_path_get(VALUE self) {
|
|
|
3002
4297
|
*/
|
|
3003
4298
|
static VALUE ruby_curl_easy_multi_get(VALUE self) {
|
|
3004
4299
|
ruby_curl_easy *rbce;
|
|
3005
|
-
|
|
4300
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3006
4301
|
return rbce->multi;
|
|
3007
4302
|
}
|
|
3008
4303
|
|
|
@@ -3012,7 +4307,12 @@ static VALUE ruby_curl_easy_multi_get(VALUE self) {
|
|
|
3012
4307
|
*/
|
|
3013
4308
|
static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
3014
4309
|
ruby_curl_easy *rbce;
|
|
3015
|
-
|
|
4310
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4311
|
+
|
|
4312
|
+
if (!NIL_P(multi) && rb_obj_is_kind_of(multi, cCurlMulti) != Qtrue) {
|
|
4313
|
+
rb_raise(rb_eTypeError, "expected Curl::Multi or nil");
|
|
4314
|
+
}
|
|
4315
|
+
|
|
3016
4316
|
rbce->multi = multi;
|
|
3017
4317
|
return rbce->multi;
|
|
3018
4318
|
}
|
|
@@ -3023,21 +4323,44 @@ static VALUE ruby_curl_easy_multi_set(VALUE self, VALUE multi) {
|
|
|
3023
4323
|
*/
|
|
3024
4324
|
static VALUE ruby_curl_easy_last_result(VALUE self) {
|
|
3025
4325
|
ruby_curl_easy *rbce;
|
|
3026
|
-
|
|
3027
|
-
return
|
|
4326
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4327
|
+
return LONG2NUM(rbce->last_result);
|
|
4328
|
+
}
|
|
4329
|
+
|
|
4330
|
+
/*
|
|
4331
|
+
* call-seq:
|
|
4332
|
+
* easy.last_error => "Error details" or nil
|
|
4333
|
+
*/
|
|
4334
|
+
static VALUE ruby_curl_easy_last_error(VALUE self) {
|
|
4335
|
+
ruby_curl_easy *rbce;
|
|
4336
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
4337
|
+
|
|
4338
|
+
if (rbce->err_buf[0]) { // curl returns NULL or empty string if none
|
|
4339
|
+
return rb_str_new2(rbce->err_buf);
|
|
4340
|
+
} else {
|
|
4341
|
+
return Qnil;
|
|
4342
|
+
}
|
|
3028
4343
|
}
|
|
3029
4344
|
|
|
3030
4345
|
/*
|
|
3031
4346
|
* call-seq:
|
|
3032
|
-
* easy.setopt
|
|
4347
|
+
* easy.setopt(opt, val) => val
|
|
3033
4348
|
*
|
|
3034
|
-
*
|
|
4349
|
+
* Initial access to libcurl curl_easy_setopt
|
|
4350
|
+
*
|
|
4351
|
+
* @param [Fixnum] opt The option to set, see +Curl::CURLOPT_*+ constants
|
|
4352
|
+
* @param [Object] val
|
|
4353
|
+
* @return [Object] val
|
|
4354
|
+
* @raise [TypeError] if the option is not supported
|
|
4355
|
+
* @note Some options - like url or cookie - aren't set directly throught +curl_easy_setopt+, but stored in the Ruby object state.
|
|
4356
|
+
* @note When +curl_easy_setopt+ is called, return value is not checked here.
|
|
3035
4357
|
*/
|
|
3036
4358
|
static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3037
4359
|
ruby_curl_easy *rbce;
|
|
3038
|
-
long option =
|
|
4360
|
+
long option = NUM2LONG(opt);
|
|
4361
|
+
rb_io_t *open_f_ptr;
|
|
3039
4362
|
|
|
3040
|
-
|
|
4363
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3041
4364
|
|
|
3042
4365
|
switch (option) {
|
|
3043
4366
|
/* BEHAVIOR OPTIONS */
|
|
@@ -3059,9 +4382,11 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3059
4382
|
case CURLOPT_CUSTOMREQUEST:
|
|
3060
4383
|
curl_easy_setopt(rbce->curl, CURLOPT_CUSTOMREQUEST, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
3061
4384
|
break;
|
|
3062
|
-
case CURLOPT_HTTP_VERSION:
|
|
3063
|
-
|
|
3064
|
-
|
|
4385
|
+
case CURLOPT_HTTP_VERSION: {
|
|
4386
|
+
long http_version = NIL_P(val) ? CURL_HTTP_VERSION_NONE : NUM2LONG(val);
|
|
4387
|
+
rbce->http_version = http_version;
|
|
4388
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HTTP_VERSION, http_version);
|
|
4389
|
+
} break;
|
|
3065
4390
|
case CURLOPT_PROXY: {
|
|
3066
4391
|
VALUE proxy_url = val;
|
|
3067
4392
|
CURB_OBJECT_HSETTER(ruby_curl_easy, proxy_url);
|
|
@@ -3073,6 +4398,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3073
4398
|
case CURLOPT_HEADER:
|
|
3074
4399
|
case CURLOPT_NOPROGRESS:
|
|
3075
4400
|
case CURLOPT_NOSIGNAL:
|
|
4401
|
+
#ifdef HAVE_CURLOPT_PATH_AS_IS
|
|
4402
|
+
case CURLOPT_PATH_AS_IS:
|
|
4403
|
+
#endif
|
|
4404
|
+
#ifdef HAVE_CURLOPT_PIPEWAIT
|
|
4405
|
+
case CURLOPT_PIPEWAIT:
|
|
4406
|
+
#endif
|
|
3076
4407
|
case CURLOPT_HTTPGET:
|
|
3077
4408
|
case CURLOPT_NOBODY: {
|
|
3078
4409
|
int type = rb_type(val);
|
|
@@ -3084,8 +4415,17 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3084
4415
|
} else {
|
|
3085
4416
|
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
3086
4417
|
}
|
|
3087
|
-
curl_easy_setopt(rbce->curl, option,
|
|
4418
|
+
curl_easy_setopt(rbce->curl, option, NUM2LONG(value));
|
|
3088
4419
|
} break;
|
|
4420
|
+
case CURLOPT_POST: {
|
|
4421
|
+
curl_easy_setopt(rbce->curl, CURLOPT_POST, rb_type(val) == T_TRUE);
|
|
4422
|
+
} break;
|
|
4423
|
+
case CURLOPT_MAXCONNECTS: {
|
|
4424
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXCONNECTS, NUM2LONG(val));
|
|
4425
|
+
} break;
|
|
4426
|
+
case CURLOPT_POSTFIELDS: {
|
|
4427
|
+
ruby_curl_easy_post_body_set_with_mode(self, val, 0);
|
|
4428
|
+
} break;
|
|
3089
4429
|
case CURLOPT_USERPWD: {
|
|
3090
4430
|
VALUE userpwd = val;
|
|
3091
4431
|
CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
|
|
@@ -3094,6 +4434,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3094
4434
|
VALUE proxypwd = val;
|
|
3095
4435
|
CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
|
|
3096
4436
|
} break;
|
|
4437
|
+
#ifdef HAVE_CURLOPT_NOPROXY
|
|
4438
|
+
case CURLOPT_NOPROXY: {
|
|
4439
|
+
VALUE noproxy = val;
|
|
4440
|
+
CURB_OBJECT_HSETTER(ruby_curl_easy, noproxy);
|
|
4441
|
+
} break;
|
|
4442
|
+
#endif
|
|
3097
4443
|
case CURLOPT_COOKIE: {
|
|
3098
4444
|
VALUE cookies = val;
|
|
3099
4445
|
CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
|
|
@@ -3106,14 +4452,205 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3106
4452
|
VALUE cookiejar = val;
|
|
3107
4453
|
CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
|
|
3108
4454
|
} break;
|
|
4455
|
+
#ifdef HAVE_CURLOPT_REQUEST_TARGET
|
|
4456
|
+
case CURLOPT_REQUEST_TARGET: {
|
|
4457
|
+
/* Forward request-target directly to libcurl as a string. */
|
|
4458
|
+
curl_easy_setopt(rbce->curl, CURLOPT_REQUEST_TARGET, NIL_P(val) ? NULL : StringValueCStr(val));
|
|
4459
|
+
} break;
|
|
4460
|
+
#endif
|
|
4461
|
+
case CURLOPT_TCP_NODELAY: {
|
|
4462
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_NODELAY, NUM2LONG(val));
|
|
4463
|
+
} break;
|
|
4464
|
+
/* FTP-specific toggles */
|
|
4465
|
+
#ifdef HAVE_CURLOPT_DIRLISTONLY
|
|
4466
|
+
case CURLOPT_DIRLISTONLY: {
|
|
4467
|
+
int type = rb_type(val);
|
|
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));
|
|
4477
|
+
} break;
|
|
4478
|
+
#endif
|
|
4479
|
+
#ifdef HAVE_CURLOPT_FTP_USE_EPSV
|
|
4480
|
+
case CURLOPT_FTP_USE_EPSV: {
|
|
4481
|
+
int type = rb_type(val);
|
|
4482
|
+
VALUE value;
|
|
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;
|
|
4492
|
+
#endif
|
|
4493
|
+
#ifdef HAVE_CURLOPT_FTP_USE_EPRT
|
|
4494
|
+
case CURLOPT_FTP_USE_EPRT: {
|
|
4495
|
+
int type = rb_type(val);
|
|
4496
|
+
VALUE value;
|
|
4497
|
+
if (type == T_TRUE) {
|
|
4498
|
+
value = rb_int_new(1);
|
|
4499
|
+
} else if (type == T_FALSE) {
|
|
4500
|
+
value = rb_int_new(0);
|
|
4501
|
+
} else {
|
|
4502
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
4503
|
+
}
|
|
4504
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_USE_EPRT, NUM2LONG(value));
|
|
4505
|
+
} break;
|
|
4506
|
+
#endif
|
|
4507
|
+
#ifdef HAVE_CURLOPT_FTP_SKIP_PASV_IP
|
|
4508
|
+
case CURLOPT_FTP_SKIP_PASV_IP: {
|
|
4509
|
+
int type = rb_type(val);
|
|
4510
|
+
VALUE value;
|
|
4511
|
+
if (type == T_TRUE) {
|
|
4512
|
+
value = rb_int_new(1);
|
|
4513
|
+
} else if (type == T_FALSE) {
|
|
4514
|
+
value = rb_int_new(0);
|
|
4515
|
+
} else {
|
|
4516
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
|
4517
|
+
}
|
|
4518
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FTP_SKIP_PASV_IP, NUM2LONG(value));
|
|
4519
|
+
} break;
|
|
4520
|
+
#endif
|
|
4521
|
+
case CURLOPT_RANGE: {
|
|
4522
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RANGE, StringValueCStr(val));
|
|
4523
|
+
} break;
|
|
3109
4524
|
case CURLOPT_RESUME_FROM: {
|
|
3110
|
-
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM,
|
|
4525
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, NUM2LONG(val));
|
|
3111
4526
|
} break;
|
|
3112
4527
|
case CURLOPT_FAILONERROR: {
|
|
3113
|
-
curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR,
|
|
4528
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR, NUM2LONG(val));
|
|
3114
4529
|
} break;
|
|
3115
|
-
|
|
4530
|
+
case CURLOPT_SSL_CIPHER_LIST: {
|
|
4531
|
+
curl_easy_setopt(rbce->curl, CURLOPT_SSL_CIPHER_LIST, StringValueCStr(val));
|
|
4532
|
+
} break;
|
|
4533
|
+
case CURLOPT_FORBID_REUSE: {
|
|
4534
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FORBID_REUSE, NUM2LONG(val));
|
|
4535
|
+
} break;
|
|
4536
|
+
#ifdef HAVE_CURLOPT_GSSAPI_DELEGATION
|
|
4537
|
+
case CURLOPT_GSSAPI_DELEGATION: {
|
|
4538
|
+
curl_easy_setopt(rbce->curl, CURLOPT_GSSAPI_DELEGATION, NUM2LONG(val));
|
|
4539
|
+
} break;
|
|
4540
|
+
#endif
|
|
4541
|
+
#ifdef HAVE_CURLOPT_UNIX_SOCKET_PATH
|
|
4542
|
+
case CURLOPT_UNIX_SOCKET_PATH: {
|
|
4543
|
+
curl_easy_setopt(rbce->curl, CURLOPT_UNIX_SOCKET_PATH, StringValueCStr(val));
|
|
4544
|
+
} break;
|
|
4545
|
+
#endif
|
|
4546
|
+
#ifdef HAVE_CURLOPT_MAX_SEND_SPEED_LARGE
|
|
4547
|
+
case CURLOPT_MAX_SEND_SPEED_LARGE: {
|
|
4548
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) NUM2LL(val));
|
|
4549
|
+
} break;
|
|
4550
|
+
#endif
|
|
4551
|
+
#ifdef HAVE_CURLOPT_MAX_RECV_SPEED_LARGE
|
|
4552
|
+
case CURLOPT_MAX_RECV_SPEED_LARGE: {
|
|
4553
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) NUM2LL(val));
|
|
4554
|
+
} break;
|
|
4555
|
+
#endif
|
|
4556
|
+
#ifdef HAVE_CURLOPT_MAXFILESIZE
|
|
4557
|
+
case CURLOPT_MAXFILESIZE:
|
|
4558
|
+
curl_easy_setopt(rbce->curl, CURLOPT_MAXFILESIZE, NUM2LONG(val));
|
|
4559
|
+
break;
|
|
4560
|
+
#endif
|
|
4561
|
+
#ifdef HAVE_CURLOPT_TCP_KEEPALIVE
|
|
4562
|
+
case CURLOPT_TCP_KEEPALIVE:
|
|
4563
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPALIVE, NUM2LONG(val));
|
|
4564
|
+
break;
|
|
4565
|
+
case CURLOPT_TCP_KEEPIDLE:
|
|
4566
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPIDLE, NUM2LONG(val));
|
|
4567
|
+
break;
|
|
4568
|
+
case CURLOPT_TCP_KEEPINTVL:
|
|
4569
|
+
curl_easy_setopt(rbce->curl, CURLOPT_TCP_KEEPINTVL, NUM2LONG(val));
|
|
4570
|
+
break;
|
|
4571
|
+
#endif
|
|
4572
|
+
#ifdef HAVE_CURLOPT_HAPROXYPROTOCOL
|
|
4573
|
+
case CURLOPT_HAPROXYPROTOCOL:
|
|
4574
|
+
curl_easy_setopt(rbce->curl, CURLOPT_HAPROXYPROTOCOL, NUM2LONG(val));
|
|
4575
|
+
break;
|
|
4576
|
+
#endif
|
|
4577
|
+
case CURLOPT_STDERR:
|
|
4578
|
+
// libcurl requires raw FILE pointer and this should be IO object in Ruby.
|
|
4579
|
+
// Tempfile or StringIO won't work.
|
|
4580
|
+
Check_Type(val, T_FILE);
|
|
4581
|
+
GetOpenFile(val, open_f_ptr);
|
|
4582
|
+
curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
|
|
4583
|
+
/* Retain a Ruby reference to the IO to prevent GC/finalization
|
|
4584
|
+
* while libcurl still holds and writes to the underlying FILE*. */
|
|
4585
|
+
rb_easy_set("stderr_io", val);
|
|
4586
|
+
break;
|
|
4587
|
+
case CURLOPT_PROTOCOLS:
|
|
4588
|
+
case CURLOPT_REDIR_PROTOCOLS:
|
|
4589
|
+
curl_easy_setopt(rbce->curl, option, NUM2LONG(val));
|
|
4590
|
+
break;
|
|
4591
|
+
#ifdef HAVE_CURLOPT_SSL_SESSIONID_CACHE
|
|
4592
|
+
case CURLOPT_SSL_SESSIONID_CACHE:
|
|
4593
|
+
curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
|
|
3116
4594
|
break;
|
|
4595
|
+
#endif
|
|
4596
|
+
#ifdef HAVE_CURLOPT_COOKIELIST
|
|
4597
|
+
case CURLOPT_COOKIELIST: {
|
|
4598
|
+
/* Forward to libcurl */
|
|
4599
|
+
curl_easy_setopt(rbce->curl, CURLOPT_COOKIELIST, StringValueCStr(val));
|
|
4600
|
+
/* Track whether the cookie engine should be enabled for requests.
|
|
4601
|
+
* According to libcurl docs, CURLOPT_COOKIELIST also enables the cookie engine
|
|
4602
|
+
* when provided with a non-command string. Some environments may still require
|
|
4603
|
+
* an explicit "enable" via CURLOPT_COOKIEFILE="" to send cookies on requests.
|
|
4604
|
+
* We do that in the perform setup when this flag is set.
|
|
4605
|
+
*/
|
|
4606
|
+
if (RB_TYPE_P(val, T_STRING)) {
|
|
4607
|
+
const char *s = StringValueCStr(val);
|
|
4608
|
+
if (!(strcmp(s, "ALL") == 0 || strcmp(s, "SESS") == 0 || strcmp(s, "FLUSH") == 0 || strcmp(s, "RELOAD") == 0)) {
|
|
4609
|
+
rbce->cookielist_engine_enabled = 1;
|
|
4610
|
+
}
|
|
4611
|
+
} else {
|
|
4612
|
+
/* Non-string values are unexpected; be conservative and do not enable. */
|
|
4613
|
+
}
|
|
4614
|
+
} break;
|
|
4615
|
+
#endif
|
|
4616
|
+
#ifdef HAVE_CURLOPT_PROXY_SSL_VERIFYHOST
|
|
4617
|
+
case CURLOPT_PROXY_SSL_VERIFYHOST:
|
|
4618
|
+
curl_easy_setopt(rbce->curl, CURLOPT_PROXY_SSL_VERIFYHOST, NUM2LONG(val));
|
|
4619
|
+
break;
|
|
4620
|
+
#endif
|
|
4621
|
+
#ifdef HAVE_CURLOPT_RESOLVE
|
|
4622
|
+
case CURLOPT_RESOLVE: {
|
|
4623
|
+
struct curl_slist *list = NULL;
|
|
4624
|
+
ruby_curl_easy_clear_resolve_list(rbce);
|
|
4625
|
+
if (NIL_P(val)) {
|
|
4626
|
+
/* When nil is passed, we clear any previous resolve list */
|
|
4627
|
+
list = NULL;
|
|
4628
|
+
} else if (TYPE(val) == T_ARRAY) {
|
|
4629
|
+
long i, len = RARRAY_LEN(val);
|
|
4630
|
+
for (i = 0; i < len; i++) {
|
|
4631
|
+
VALUE item = rb_ary_entry(val, i);
|
|
4632
|
+
struct curl_slist *new_list = curl_slist_append(list, StringValueCStr(item));
|
|
4633
|
+
if (!new_list) {
|
|
4634
|
+
curl_slist_free_all(list);
|
|
4635
|
+
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
4636
|
+
}
|
|
4637
|
+
list = new_list;
|
|
4638
|
+
}
|
|
4639
|
+
} else {
|
|
4640
|
+
/* If a single string is passed, use it directly */
|
|
4641
|
+
list = curl_slist_append(NULL, StringValueCStr(val));
|
|
4642
|
+
if (!list) {
|
|
4643
|
+
rb_raise(rb_eNoMemError, "Failed to create resolve list");
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
/* Save the list pointer in the ruby_curl_easy structure for cleanup later */
|
|
4647
|
+
rbce->curl_resolve = list;
|
|
4648
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("resolve"), val);
|
|
4649
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESOLVE, list);
|
|
4650
|
+
} break;
|
|
4651
|
+
#endif
|
|
4652
|
+
default:
|
|
4653
|
+
rb_raise(rb_eTypeError, "Curb unsupported option");
|
|
3117
4654
|
}
|
|
3118
4655
|
|
|
3119
4656
|
return val;
|
|
@@ -3121,9 +4658,13 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
3121
4658
|
|
|
3122
4659
|
/*
|
|
3123
4660
|
* call-seq:
|
|
3124
|
-
* easy.getinfo
|
|
4661
|
+
* easy.getinfo(opt) => nil
|
|
3125
4662
|
*
|
|
3126
4663
|
* Iniital access to libcurl curl_easy_getinfo, remember getinfo doesn't return the same values as setopt
|
|
4664
|
+
*
|
|
4665
|
+
* @note This method is not implemented yet.
|
|
4666
|
+
* @param [Fixnum] code Constant +CURLINFO_*+ from libcurl
|
|
4667
|
+
* @return [nil]
|
|
3127
4668
|
*/
|
|
3128
4669
|
static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
|
|
3129
4670
|
return Qnil;
|
|
@@ -3136,7 +4677,7 @@ static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
|
|
|
3136
4677
|
static VALUE ruby_curl_easy_inspect(VALUE self) {
|
|
3137
4678
|
char buf[64];
|
|
3138
4679
|
ruby_curl_easy *rbce;
|
|
3139
|
-
|
|
4680
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3140
4681
|
/* if we don't have a url set... we'll crash... */
|
|
3141
4682
|
if( !rb_easy_nil("url") && rb_easy_type_check("url", T_STRING)) {
|
|
3142
4683
|
VALUE url = rb_easy_get("url");
|
|
@@ -3168,7 +4709,7 @@ static VALUE ruby_curl_easy_escape(VALUE self, VALUE svalue) {
|
|
|
3168
4709
|
VALUE rresult;
|
|
3169
4710
|
VALUE str = svalue;
|
|
3170
4711
|
|
|
3171
|
-
|
|
4712
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3172
4713
|
|
|
3173
4714
|
/* NOTE: make sure the value is a string, if not call to_s */
|
|
3174
4715
|
if( rb_type(str) != T_STRING ) { str = rb_funcall(str,rb_intern("to_s"),0); }
|
|
@@ -3199,12 +4740,12 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
|
|
|
3199
4740
|
char *result;
|
|
3200
4741
|
VALUE rresult;
|
|
3201
4742
|
|
|
3202
|
-
|
|
4743
|
+
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
3203
4744
|
|
|
3204
4745
|
#if (LIBCURL_VERSION_NUM >= 0x070f04)
|
|
3205
4746
|
result = (char*)curl_easy_unescape(rbce->curl, StringValuePtr(str), (int)RSTRING_LEN(str), &rlen);
|
|
3206
4747
|
#else
|
|
3207
|
-
result = (char*)curl_unescape(StringValuePtr(str), RSTRING_LEN(str));
|
|
4748
|
+
result = (char*)curl_unescape(StringValuePtr(str), (int)RSTRING_LEN(str));
|
|
3208
4749
|
rlen = strlen(result);
|
|
3209
4750
|
#endif
|
|
3210
4751
|
|
|
@@ -3219,15 +4760,16 @@ static VALUE ruby_curl_easy_unescape(VALUE self, VALUE str) {
|
|
|
3219
4760
|
|
|
3220
4761
|
/*
|
|
3221
4762
|
* call-seq:
|
|
3222
|
-
* Curl::Easy.error(code) => String
|
|
4763
|
+
* Curl::Easy.error(code) => [ErrCode, String]
|
|
3223
4764
|
*
|
|
3224
4765
|
* translate an internal libcurl error to ruby error class
|
|
3225
4766
|
*/
|
|
3226
4767
|
static VALUE ruby_curl_easy_error_message(VALUE klass, VALUE code) {
|
|
3227
|
-
return rb_curl_easy_error(
|
|
4768
|
+
return rb_curl_easy_error(NUM2INT(code));
|
|
3228
4769
|
}
|
|
3229
4770
|
|
|
3230
4771
|
/* =================== INIT LIB =====================*/
|
|
4772
|
+
// TODO: https://bugs.ruby-lang.org/issues/18007
|
|
3231
4773
|
void init_curb_easy() {
|
|
3232
4774
|
idCall = rb_intern("call");
|
|
3233
4775
|
idJoin = rb_intern("join");
|
|
@@ -3238,12 +4780,21 @@ void init_curb_easy() {
|
|
|
3238
4780
|
cCurlEasy = rb_define_class_under(mCurl, "Easy", rb_cObject);
|
|
3239
4781
|
|
|
3240
4782
|
/* Class methods */
|
|
3241
|
-
|
|
4783
|
+
rb_define_alloc_func(cCurlEasy, ruby_curl_easy_allocate);
|
|
3242
4784
|
rb_define_singleton_method(cCurlEasy, "error", ruby_curl_easy_error_message, 1);
|
|
3243
4785
|
|
|
4786
|
+
/* Initialize method */
|
|
4787
|
+
rb_define_method(cCurlEasy, "initialize", ruby_curl_easy_initialize, -1);
|
|
4788
|
+
|
|
3244
4789
|
/* Attributes for config next perform */
|
|
3245
4790
|
rb_define_method(cCurlEasy, "url", ruby_curl_easy_url_get, 0);
|
|
3246
4791
|
rb_define_method(cCurlEasy, "proxy_url", ruby_curl_easy_proxy_url_get, 0);
|
|
4792
|
+
rb_define_method(cCurlEasy, "http_version=", ruby_curl_easy_http_version_set, 1);
|
|
4793
|
+
rb_define_method(cCurlEasy, "http_version", ruby_curl_easy_http_version_get, 0);
|
|
4794
|
+
|
|
4795
|
+
rb_define_method(cCurlEasy, "proxy_headers=", ruby_curl_easy_proxy_headers_set, 1);
|
|
4796
|
+
rb_define_method(cCurlEasy, "proxy_headers", ruby_curl_easy_proxy_headers_get, 0);
|
|
4797
|
+
|
|
3247
4798
|
rb_define_method(cCurlEasy, "headers=", ruby_curl_easy_headers_set, 1);
|
|
3248
4799
|
rb_define_method(cCurlEasy, "headers", ruby_curl_easy_headers_get, 0);
|
|
3249
4800
|
rb_define_method(cCurlEasy, "interface", ruby_curl_easy_interface_get, 0);
|
|
@@ -3270,6 +4821,8 @@ void init_curb_easy() {
|
|
|
3270
4821
|
rb_define_method(cCurlEasy, "put_data=", ruby_curl_easy_put_data_set, 1);
|
|
3271
4822
|
rb_define_method(cCurlEasy, "ftp_commands=", ruby_curl_easy_ftp_commands_set, 1);
|
|
3272
4823
|
rb_define_method(cCurlEasy, "ftp_commands", ruby_curl_easy_ftp_commands_get, 0);
|
|
4824
|
+
rb_define_method(cCurlEasy, "resolve=", ruby_curl_easy_resolve_set, 1);
|
|
4825
|
+
rb_define_method(cCurlEasy, "resolve", ruby_curl_easy_resolve_get, 0);
|
|
3273
4826
|
|
|
3274
4827
|
rb_define_method(cCurlEasy, "local_port=", ruby_curl_easy_local_port_set, 1);
|
|
3275
4828
|
rb_define_method(cCurlEasy, "local_port", ruby_curl_easy_local_port_get, 0);
|
|
@@ -3287,8 +4840,12 @@ void init_curb_easy() {
|
|
|
3287
4840
|
rb_define_method(cCurlEasy, "max_redirects", ruby_curl_easy_max_redirects_get, 0);
|
|
3288
4841
|
rb_define_method(cCurlEasy, "timeout=", ruby_curl_easy_timeout_set, 1);
|
|
3289
4842
|
rb_define_method(cCurlEasy, "timeout", ruby_curl_easy_timeout_get, 0);
|
|
4843
|
+
rb_define_method(cCurlEasy, "timeout_ms=", ruby_curl_easy_timeout_ms_set, 1);
|
|
4844
|
+
rb_define_method(cCurlEasy, "timeout_ms", ruby_curl_easy_timeout_ms_get, 0);
|
|
3290
4845
|
rb_define_method(cCurlEasy, "connect_timeout=", ruby_curl_easy_connect_timeout_set, 1);
|
|
3291
4846
|
rb_define_method(cCurlEasy, "connect_timeout", ruby_curl_easy_connect_timeout_get, 0);
|
|
4847
|
+
rb_define_method(cCurlEasy, "connect_timeout_ms=", ruby_curl_easy_connect_timeout_ms_set, 1);
|
|
4848
|
+
rb_define_method(cCurlEasy, "connect_timeout_ms", ruby_curl_easy_connect_timeout_ms_get, 0);
|
|
3292
4849
|
rb_define_method(cCurlEasy, "dns_cache_timeout=", ruby_curl_easy_dns_cache_timeout_set, 1);
|
|
3293
4850
|
rb_define_method(cCurlEasy, "dns_cache_timeout", ruby_curl_easy_dns_cache_timeout_get, 0);
|
|
3294
4851
|
rb_define_method(cCurlEasy, "ftp_response_timeout=", ruby_curl_easy_ftp_response_timeout_set, 1);
|
|
@@ -3297,6 +4854,10 @@ void init_curb_easy() {
|
|
|
3297
4854
|
rb_define_method(cCurlEasy, "low_speed_limit", ruby_curl_easy_low_speed_limit_get, 0);
|
|
3298
4855
|
rb_define_method(cCurlEasy, "low_speed_time=", ruby_curl_easy_low_speed_time_set, 1);
|
|
3299
4856
|
rb_define_method(cCurlEasy, "low_speed_time", ruby_curl_easy_low_speed_time_get, 0);
|
|
4857
|
+
rb_define_method(cCurlEasy, "max_send_speed_large=", ruby_curl_easy_max_send_speed_large_set, 1);
|
|
4858
|
+
rb_define_method(cCurlEasy, "max_send_speed_large", ruby_curl_easy_max_send_speed_large_get, 0);
|
|
4859
|
+
rb_define_method(cCurlEasy, "max_recv_speed_large=", ruby_curl_easy_max_recv_speed_large_set, 1);
|
|
4860
|
+
rb_define_method(cCurlEasy, "max_recv_speed_large", ruby_curl_easy_max_recv_speed_large_get, 0);
|
|
3300
4861
|
rb_define_method(cCurlEasy, "ssl_version=", ruby_curl_easy_ssl_version_set, 1);
|
|
3301
4862
|
rb_define_method(cCurlEasy, "ssl_version", ruby_curl_easy_ssl_version_get, 0);
|
|
3302
4863
|
rb_define_method(cCurlEasy, "use_ssl=", ruby_curl_easy_use_ssl_set, 1);
|
|
@@ -3348,7 +4909,8 @@ void init_curb_easy() {
|
|
|
3348
4909
|
|
|
3349
4910
|
rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
|
|
3350
4911
|
rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
|
|
3351
|
-
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
|
|
4912
|
+
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, -1);
|
|
4913
|
+
rb_define_method(cCurlEasy, "http_patch", ruby_curl_easy_perform_patch, -1);
|
|
3352
4914
|
|
|
3353
4915
|
/* Post-perform info methods */
|
|
3354
4916
|
rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
|
|
@@ -3356,6 +4918,7 @@ void init_curb_easy() {
|
|
|
3356
4918
|
|
|
3357
4919
|
rb_define_method(cCurlEasy, "last_effective_url", ruby_curl_easy_last_effective_url_get, 0);
|
|
3358
4920
|
rb_define_method(cCurlEasy, "response_code", ruby_curl_easy_response_code_get, 0);
|
|
4921
|
+
rb_define_method(cCurlEasy, "code", ruby_curl_easy_response_code_get, 0);
|
|
3359
4922
|
#if defined(HAVE_CURLINFO_PRIMARY_IP)
|
|
3360
4923
|
rb_define_method(cCurlEasy, "primary_ip", ruby_curl_easy_primary_ip_get, 0);
|
|
3361
4924
|
#endif
|
|
@@ -3364,6 +4927,9 @@ void init_curb_easy() {
|
|
|
3364
4927
|
rb_define_method(cCurlEasy, "total_time", ruby_curl_easy_total_time_get, 0);
|
|
3365
4928
|
rb_define_method(cCurlEasy, "name_lookup_time", ruby_curl_easy_name_lookup_time_get, 0);
|
|
3366
4929
|
rb_define_method(cCurlEasy, "connect_time", ruby_curl_easy_connect_time_get, 0);
|
|
4930
|
+
#if defined(HAVE_CURLINFO_APPCONNECT_TIME)
|
|
4931
|
+
rb_define_method(cCurlEasy, "app_connect_time", ruby_curl_easy_app_connect_time_get, 0);
|
|
4932
|
+
#endif
|
|
3367
4933
|
rb_define_method(cCurlEasy, "pre_transfer_time", ruby_curl_easy_pre_transfer_time_get, 0);
|
|
3368
4934
|
rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
|
|
3369
4935
|
rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
|
|
@@ -3381,6 +4947,7 @@ void init_curb_easy() {
|
|
|
3381
4947
|
rb_define_method(cCurlEasy, "content_type", ruby_curl_easy_content_type_get, 0);
|
|
3382
4948
|
rb_define_method(cCurlEasy, "os_errno", ruby_curl_easy_os_errno_get, 0);
|
|
3383
4949
|
rb_define_method(cCurlEasy, "num_connects", ruby_curl_easy_num_connects_get, 0);
|
|
4950
|
+
rb_define_method(cCurlEasy, "cookielist", ruby_curl_easy_cookielist_get, 0);
|
|
3384
4951
|
rb_define_method(cCurlEasy, "ftp_entry_path", ruby_curl_easy_ftp_entry_path_get, 0);
|
|
3385
4952
|
|
|
3386
4953
|
rb_define_method(cCurlEasy, "close", ruby_curl_easy_close, 0);
|
|
@@ -3397,7 +4964,9 @@ void init_curb_easy() {
|
|
|
3397
4964
|
|
|
3398
4965
|
rb_define_method(cCurlEasy, "multi", ruby_curl_easy_multi_get, 0);
|
|
3399
4966
|
rb_define_method(cCurlEasy, "multi=", ruby_curl_easy_multi_set, 1);
|
|
4967
|
+
rb_define_private_method(cCurlEasy, "_take_callback_error", ruby_curl_easy_take_callback_error, 0);
|
|
3400
4968
|
rb_define_method(cCurlEasy, "last_result", ruby_curl_easy_last_result, 0);
|
|
4969
|
+
rb_define_method(cCurlEasy, "last_error", ruby_curl_easy_last_error, 0);
|
|
3401
4970
|
|
|
3402
4971
|
rb_define_method(cCurlEasy, "setopt", ruby_curl_easy_set_opt, 2);
|
|
3403
4972
|
rb_define_method(cCurlEasy, "getinfo", ruby_curl_easy_get_opt, 1);
|