curb 1.3.1 → 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/curb.h +3 -3
- data/ext/curb_easy.c +285 -142
- data/ext/curb_multi.c +185 -20
- data/ext/curb_multi.h +3 -0
- data/ext/curb_postfield.c +1 -0
- data/tests/bug_curb_easy_blocks_ruby_threads.rb +3 -3
- data/tests/bug_follow_redirect_288.rb +7 -7
- data/tests/bug_raise_on_callback.rb +4 -3
- data/tests/helper.rb +7 -0
- data/tests/tc_curl_easy.rb +116 -0
- data/tests/tc_curl_easy_resolve.rb +32 -0
- data/tests/tc_curl_multi.rb +56 -0
- data/tests/tc_curl_native_coverage.rb +15 -0
- data/tests/tc_curl_postfield.rb +15 -0
- data/tests/tc_ftp_options.rb +14 -1
- metadata +2 -2
data/ext/curb_easy.c
CHANGED
|
@@ -107,6 +107,11 @@ static VALUE call_stream_to_s(VALUE stream) {
|
|
|
107
107
|
return rb_funcall(stream, rb_intern("to_s"), 0);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
static VALUE call_string_value(VALUE str) {
|
|
111
|
+
StringValue(str);
|
|
112
|
+
return str;
|
|
113
|
+
}
|
|
114
|
+
|
|
110
115
|
struct stream_seek_call_args {
|
|
111
116
|
VALUE stream;
|
|
112
117
|
curl_off_t offset;
|
|
@@ -141,6 +146,30 @@ static VALUE call_with_easy_callback_active(VALUE argp) {
|
|
|
141
146
|
return with_easy_callback_active(args->rbce, args->func, args->arg);
|
|
142
147
|
}
|
|
143
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
|
+
|
|
144
173
|
/* Default body handler appends to easy.body_data buffer */
|
|
145
174
|
static size_t default_body_handler(char *stream,
|
|
146
175
|
size_t size,
|
|
@@ -178,18 +207,36 @@ static size_t read_data_handler(void *ptr,
|
|
|
178
207
|
ruby_curl_easy *rbce) {
|
|
179
208
|
VALUE upload = rb_easy_get("upload");
|
|
180
209
|
size_t read_bytes = (size*nmemb);
|
|
181
|
-
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);
|
|
182
217
|
|
|
183
218
|
if (rb_respond_to(stream, rb_intern("read"))) {//if (rb_respond_to(stream, rb_intern("to_s"))) {
|
|
184
219
|
/* copy read_bytes from stream into ptr */
|
|
185
220
|
struct stream_read_call_args args;
|
|
186
221
|
args.stream = stream;
|
|
187
222
|
args.read_bytes = read_bytes;
|
|
188
|
-
VALUE str =
|
|
223
|
+
VALUE str = rescue_easy_callback(rbce, call_stream_read, (VALUE)&args);
|
|
189
224
|
if( str != Qnil ) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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;
|
|
193
240
|
}
|
|
194
241
|
else {
|
|
195
242
|
return 0;
|
|
@@ -202,9 +249,17 @@ static size_t read_data_handler(void *ptr,
|
|
|
202
249
|
size_t remaining;
|
|
203
250
|
char *str_ptr;
|
|
204
251
|
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
205
|
-
str =
|
|
206
|
-
|
|
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
|
+
|
|
207
258
|
len = RSTRING_LEN(str);
|
|
259
|
+
if (rbcu->offset >= len) {
|
|
260
|
+
return 0;
|
|
261
|
+
}
|
|
262
|
+
|
|
208
263
|
remaining = len - rbcu->offset;
|
|
209
264
|
str_ptr = RSTRING_PTR(str);
|
|
210
265
|
|
|
@@ -232,14 +287,23 @@ int seek_data_handler(ruby_curl_easy *rbce,
|
|
|
232
287
|
int origin) {
|
|
233
288
|
|
|
234
289
|
VALUE upload = rb_easy_get("upload");
|
|
235
|
-
VALUE stream
|
|
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);
|
|
236
297
|
|
|
237
298
|
if (rb_respond_to(stream, rb_intern("seek"))) {
|
|
238
299
|
struct stream_seek_call_args args;
|
|
239
300
|
args.stream = stream;
|
|
240
301
|
args.offset = offset;
|
|
241
|
-
args.origin =
|
|
242
|
-
|
|
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
|
+
}
|
|
243
307
|
} else {
|
|
244
308
|
ruby_curl_upload *rbcu;
|
|
245
309
|
TypedData_Get_Struct(upload, ruby_curl_upload, &ruby_curl_upload_data_type, rbcu);
|
|
@@ -725,6 +789,24 @@ static struct curl_slist *duplicate_curl_slist(struct curl_slist *list) {
|
|
|
725
789
|
return dup;
|
|
726
790
|
}
|
|
727
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;
|
|
808
|
+
}
|
|
809
|
+
|
|
728
810
|
/*
|
|
729
811
|
* call-seq:
|
|
730
812
|
* easy.clone => <easy clone>
|
|
@@ -747,6 +829,10 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
747
829
|
|
|
748
830
|
/* now deep copy */
|
|
749
831
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
|
832
|
+
if (!newrbce->curl) {
|
|
833
|
+
free(newrbce);
|
|
834
|
+
rb_raise(rb_eNoMemError, "Failed to duplicate Curl::Easy handle");
|
|
835
|
+
}
|
|
750
836
|
newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
|
|
751
837
|
newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
|
|
752
838
|
newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
|
|
@@ -763,6 +849,21 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
763
849
|
/* Set the error buffer on the new curl handle using the new err_buf */
|
|
764
850
|
curl_easy_setopt(newrbce->curl, CURLOPT_ERRORBUFFER, newrbce->err_buf);
|
|
765
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
|
+
|
|
766
867
|
VALUE clone = TypedData_Wrap_Struct(cCurlEasy, &ruby_curl_easy_data_type, newrbce);
|
|
767
868
|
newrbce->self = clone;
|
|
768
869
|
curl_easy_setopt(newrbce->curl, CURLOPT_PRIVATE, (void*)newrbce);
|
|
@@ -801,6 +902,8 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
801
902
|
ruby_curl_easy_zero(rbce);
|
|
802
903
|
rbce->self = self;
|
|
803
904
|
|
|
905
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, rbce->err_buf);
|
|
906
|
+
|
|
804
907
|
/* give the new curl handle a reference back to the ruby object */
|
|
805
908
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
806
909
|
if (ecode != CURLE_OK) {
|
|
@@ -1268,35 +1371,15 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
1268
1371
|
ruby_curl_easy *rbce;
|
|
1269
1372
|
CURL *curl;
|
|
1270
1373
|
VALUE upload;
|
|
1374
|
+
VALUE upload_stream = data;
|
|
1271
1375
|
VALUE headers;
|
|
1376
|
+
VALUE infile_size = Qnil;
|
|
1272
1377
|
|
|
1273
1378
|
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
1274
1379
|
|
|
1275
|
-
upload = ruby_curl_upload_new(cCurlUpload);
|
|
1276
|
-
ruby_curl_upload_stream_set(upload,data);
|
|
1277
|
-
|
|
1278
|
-
curl = rbce->curl;
|
|
1279
|
-
rb_easy_set("upload", upload); /* keep the upload object alive as long as
|
|
1280
|
-
the easy handle is active or until the upload
|
|
1281
|
-
is complete or terminated... */
|
|
1282
|
-
|
|
1283
|
-
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
|
1284
|
-
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
1285
|
-
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, NULL);
|
|
1286
|
-
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 0);
|
|
1287
|
-
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
|
|
1288
|
-
curl_easy_setopt(curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
1289
|
-
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
1290
|
-
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
|
|
1291
|
-
#endif
|
|
1292
|
-
curl_easy_setopt(curl, CURLOPT_READDATA, rbce);
|
|
1293
|
-
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
1294
|
-
curl_easy_setopt(curl, CURLOPT_SEEKDATA, rbce);
|
|
1295
|
-
#endif
|
|
1296
|
-
|
|
1297
1380
|
/*
|
|
1298
|
-
*
|
|
1299
|
-
*
|
|
1381
|
+
* Validate and prepare Ruby-visible state before mutating the CURL handle.
|
|
1382
|
+
* Several branches below can raise (header type, stat, size, to_s).
|
|
1300
1383
|
*/
|
|
1301
1384
|
if (!rb_easy_nil("headers")) {
|
|
1302
1385
|
if (rb_easy_type_check("headers", T_ARRAY) || rb_easy_type_check("headers", T_STRING)) {
|
|
@@ -1304,43 +1387,80 @@ static VALUE ruby_curl_easy_put_data_set(VALUE self, VALUE data) {
|
|
|
1304
1387
|
}
|
|
1305
1388
|
}
|
|
1306
1389
|
|
|
1307
|
-
|
|
1308
|
-
|
|
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
|
+
}
|
|
1309
1397
|
|
|
1310
1398
|
headers = rb_easy_get("headers");
|
|
1311
1399
|
if( headers == Qnil ) {
|
|
1312
1400
|
headers = rb_hash_new();
|
|
1313
1401
|
}
|
|
1314
1402
|
|
|
1315
|
-
if (rb_respond_to(data, rb_intern("read"))) {
|
|
1316
|
-
VALUE stat =
|
|
1317
|
-
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) {
|
|
1318
1409
|
VALUE size;
|
|
1319
1410
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
|
1320
1411
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
|
1321
1412
|
}
|
|
1322
1413
|
size = rb_funcall(stat, rb_intern("size"), 0);
|
|
1323
|
-
|
|
1414
|
+
infile_size = size;
|
|
1324
1415
|
}
|
|
1325
1416
|
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) == Qnil && rb_hash_aref(headers, rb_str_new2("Transfer-Encoding")) == Qnil ) {
|
|
1326
1417
|
rb_hash_aset(headers, rb_str_new2("Transfer-Encoding"), rb_str_new2("chunked"));
|
|
1327
1418
|
}
|
|
1328
1419
|
else if( rb_hash_aref(headers, rb_str_new2("Content-Length")) ) {
|
|
1329
1420
|
VALUE size = rb_funcall(rb_hash_aref(headers, rb_str_new2("Content-Length")), rb_intern("to_i"), 0);
|
|
1330
|
-
|
|
1421
|
+
infile_size = size;
|
|
1331
1422
|
}
|
|
1332
1423
|
}
|
|
1333
|
-
else if (rb_respond_to(data, rb_intern("to_s"))) {
|
|
1334
|
-
|
|
1424
|
+
else if (!NIL_P(data) && rb_respond_to(data, rb_intern("to_s"))) {
|
|
1425
|
+
infile_size = LONG2NUM(RSTRING_LEN(upload_stream));
|
|
1335
1426
|
if( rb_hash_aref(headers, rb_str_new2("Expect")) == Qnil ) {
|
|
1336
1427
|
rb_hash_aset(headers, rb_str_new2("Expect"), rb_str_new2(""));
|
|
1337
1428
|
}
|
|
1338
1429
|
}
|
|
1430
|
+
else if (NIL_P(data)) {
|
|
1431
|
+
/* Preserve legacy nil handling: configure an upload with no payload. */
|
|
1432
|
+
}
|
|
1339
1433
|
else {
|
|
1340
1434
|
rb_raise(rb_eRuntimeError, "PUT data must respond to read or to_s");
|
|
1341
1435
|
}
|
|
1342
1436
|
rb_easy_set("headers",headers);
|
|
1343
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
|
+
|
|
1344
1464
|
// if we made it this far, all should be well.
|
|
1345
1465
|
return data;
|
|
1346
1466
|
}
|
|
@@ -2655,7 +2775,7 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap, int _c, const VA
|
|
|
2655
2775
|
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
2656
2776
|
|
|
2657
2777
|
ftp_command_string = rb_obj_as_string(ftp_command);
|
|
2658
|
-
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(
|
|
2778
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(ftp_command_string));
|
|
2659
2779
|
if (!new_list) {
|
|
2660
2780
|
rb_raise(rb_eNoMemError, "Failed to append to FTP command list");
|
|
2661
2781
|
}
|
|
@@ -2673,7 +2793,7 @@ static VALUE cb_each_resolve(VALUE resolve, VALUE wrap, int _c, const VALUE *_pt
|
|
|
2673
2793
|
TypedData_Get_Struct(wrap, struct curl_slist *, &curl_slist_ptr_type, list);
|
|
2674
2794
|
|
|
2675
2795
|
resolve_string = rb_obj_as_string(resolve);
|
|
2676
|
-
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(
|
|
2796
|
+
struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(resolve_string));
|
|
2677
2797
|
if (!new_list) {
|
|
2678
2798
|
rb_raise(rb_eNoMemError, "Failed to append to resolve list");
|
|
2679
2799
|
}
|
|
@@ -3054,6 +3174,13 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
|
|
3054
3174
|
if (rb_easy_type_check("resolve", T_ARRAY)) {
|
|
3055
3175
|
VALUE wrap = TypedData_Wrap_Struct(rb_cObject, &curl_slist_ptr_type, rslv);
|
|
3056
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;
|
|
3057
3184
|
}
|
|
3058
3185
|
|
|
3059
3186
|
if (*rslv) {
|
|
@@ -3095,6 +3222,12 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
|
3095
3222
|
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
|
3096
3223
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
|
3097
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
|
|
3098
3231
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
|
3099
3232
|
}
|
|
3100
3233
|
|
|
@@ -3104,6 +3237,44 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
|
3104
3237
|
return Qnil;
|
|
3105
3238
|
}
|
|
3106
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;
|
|
3256
|
+
|
|
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
|
+
}
|
|
3273
|
+
}
|
|
3274
|
+
|
|
3275
|
+
return Qnil;
|
|
3276
|
+
}
|
|
3277
|
+
|
|
3107
3278
|
/*
|
|
3108
3279
|
* Common implementation of easy.http(verb) and easy.http_delete
|
|
3109
3280
|
*/
|
|
@@ -3136,13 +3307,9 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
|
3136
3307
|
curl_easy_setopt(curl, CURLOPT_POST, 0L);
|
|
3137
3308
|
}
|
|
3138
3309
|
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
if (is_head) {
|
|
3143
|
-
curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
|
|
3144
|
-
}
|
|
3145
|
-
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
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);
|
|
3146
3313
|
|
|
3147
3314
|
return retval;
|
|
3148
3315
|
}
|
|
@@ -3173,19 +3340,68 @@ static VALUE call_easy_perform(VALUE self) {
|
|
|
3173
3340
|
}
|
|
3174
3341
|
|
|
3175
3342
|
struct easy_form_perform_args {
|
|
3343
|
+
VALUE self;
|
|
3176
3344
|
CURL *curl;
|
|
3345
|
+
int argc;
|
|
3346
|
+
VALUE *argv;
|
|
3177
3347
|
struct curl_httppost *first;
|
|
3348
|
+
struct curl_httppost *last;
|
|
3349
|
+
int clear_customrequest;
|
|
3350
|
+
int form_set_on_curl;
|
|
3178
3351
|
};
|
|
3179
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
|
+
|
|
3180
3390
|
static VALUE ensure_free_form_post(VALUE argp) {
|
|
3181
3391
|
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
3182
3392
|
if (args->curl) {
|
|
3183
|
-
|
|
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
|
+
}
|
|
3184
3399
|
}
|
|
3185
3400
|
if (args->first) {
|
|
3186
3401
|
curl_formfree(args->first);
|
|
3187
3402
|
args->first = NULL;
|
|
3188
3403
|
}
|
|
3404
|
+
args->last = NULL;
|
|
3189
3405
|
return Qnil;
|
|
3190
3406
|
}
|
|
3191
3407
|
|
|
@@ -3216,7 +3432,6 @@ static VALUE ensure_free_form_post(VALUE argp) {
|
|
|
3216
3432
|
static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
3217
3433
|
ruby_curl_easy *rbce;
|
|
3218
3434
|
CURL *curl;
|
|
3219
|
-
int i;
|
|
3220
3435
|
VALUE args_ary;
|
|
3221
3436
|
|
|
3222
3437
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
@@ -3230,33 +3445,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
3230
3445
|
|
|
3231
3446
|
if (rbce->multipart_form_post) {
|
|
3232
3447
|
VALUE ret;
|
|
3233
|
-
struct
|
|
3234
|
-
|
|
3235
|
-
// Make the multipart form
|
|
3236
|
-
for (i = 0; i < argc; i++) {
|
|
3237
|
-
if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
|
|
3238
|
-
append_to_form(argv[i], &first, &last);
|
|
3239
|
-
} else if (rb_type(argv[i]) == T_ARRAY) {
|
|
3240
|
-
// see: https://github.com/rvanlieshout/curb/commit/8bcdefddc0162484681ebd1a92d52a642666a445
|
|
3241
|
-
long c = 0, argv_len = RARRAY_LEN(argv[i]);
|
|
3242
|
-
for (; c < argv_len; ++c) {
|
|
3243
|
-
if (rb_obj_is_instance_of(rb_ary_entry(argv[i],c), cCurlPostField)) {
|
|
3244
|
-
append_to_form(rb_ary_entry(argv[i],c), &first, &last);
|
|
3245
|
-
} else {
|
|
3246
|
-
rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
|
|
3247
|
-
return Qnil;
|
|
3248
|
-
}
|
|
3249
|
-
}
|
|
3250
|
-
} else {
|
|
3251
|
-
rb_raise(eCurlErrInvalidPostField, "You must use PostFields only with multipart form posts");
|
|
3252
|
-
return Qnil;
|
|
3253
|
-
}
|
|
3254
|
-
}
|
|
3255
|
-
|
|
3256
|
-
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
3257
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
|
|
3258
|
-
struct easy_form_perform_args perform_args = { curl, first };
|
|
3259
|
-
ret = rb_ensure(call_easy_perform, self, ensure_free_form_post, (VALUE)&perform_args);
|
|
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);
|
|
3260
3450
|
|
|
3261
3451
|
return ret;
|
|
3262
3452
|
} else {
|
|
@@ -3277,7 +3467,9 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
3277
3467
|
ruby_curl_easy_post_body_set(self, post_body);
|
|
3278
3468
|
}
|
|
3279
3469
|
|
|
3280
|
-
|
|
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);
|
|
3281
3473
|
}
|
|
3282
3474
|
}
|
|
3283
3475
|
}
|
|
@@ -3300,7 +3492,6 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
3300
3492
|
static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
3301
3493
|
ruby_curl_easy *rbce;
|
|
3302
3494
|
CURL *curl;
|
|
3303
|
-
int i;
|
|
3304
3495
|
VALUE args_ary;
|
|
3305
3496
|
|
|
3306
3497
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
@@ -3315,35 +3506,8 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
|
3315
3506
|
|
|
3316
3507
|
if (rbce->multipart_form_post) {
|
|
3317
3508
|
VALUE ret;
|
|
3318
|
-
struct
|
|
3319
|
-
|
|
3320
|
-
/* Build the multipart form (same logic as for POST) */
|
|
3321
|
-
for (i = 0; i < argc; i++) {
|
|
3322
|
-
if (rb_obj_is_instance_of(argv[i], cCurlPostField)) {
|
|
3323
|
-
append_to_form(argv[i], &first, &last);
|
|
3324
|
-
} else if (rb_type(argv[i]) == T_ARRAY) {
|
|
3325
|
-
long j, argv_len = RARRAY_LEN(argv[i]);
|
|
3326
|
-
for (j = 0; j < argv_len; ++j) {
|
|
3327
|
-
if (rb_obj_is_instance_of(rb_ary_entry(argv[i], j), cCurlPostField)) {
|
|
3328
|
-
append_to_form(rb_ary_entry(argv[i], j), &first, &last);
|
|
3329
|
-
} else {
|
|
3330
|
-
rb_raise(eCurlErrInvalidPostField,
|
|
3331
|
-
"You must use PostFields only with multipart form posts");
|
|
3332
|
-
return Qnil;
|
|
3333
|
-
}
|
|
3334
|
-
}
|
|
3335
|
-
} else {
|
|
3336
|
-
rb_raise(eCurlErrInvalidPostField,
|
|
3337
|
-
"You must use PostFields only with multipart form posts");
|
|
3338
|
-
return Qnil;
|
|
3339
|
-
}
|
|
3340
|
-
}
|
|
3341
|
-
/* Disable the POST flag */
|
|
3342
|
-
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
3343
|
-
/* Use the built multipart form as the request body */
|
|
3344
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
|
|
3345
|
-
struct easy_form_perform_args perform_args = { curl, first };
|
|
3346
|
-
ret = rb_ensure(call_easy_perform, self, ensure_free_form_post, (VALUE)&perform_args);
|
|
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);
|
|
3347
3511
|
return ret;
|
|
3348
3512
|
} else {
|
|
3349
3513
|
/* Join arguments into a raw PATCH body */
|
|
@@ -3359,7 +3523,9 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
|
3359
3523
|
if (rb_easy_nil("postdata_buffer")) {
|
|
3360
3524
|
ruby_curl_easy_post_body_set(self, patch_body);
|
|
3361
3525
|
}
|
|
3362
|
-
|
|
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);
|
|
3363
3529
|
}
|
|
3364
3530
|
}
|
|
3365
3531
|
}
|
|
@@ -3376,7 +3542,6 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
3376
3542
|
ruby_curl_easy *rbce;
|
|
3377
3543
|
CURL *curl;
|
|
3378
3544
|
VALUE args_ary;
|
|
3379
|
-
int i;
|
|
3380
3545
|
|
|
3381
3546
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
3382
3547
|
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
@@ -3399,33 +3564,8 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
3399
3564
|
/* Otherwise, if multipart_form_post is true, use multipart logic */
|
|
3400
3565
|
else if (rbce->multipart_form_post) {
|
|
3401
3566
|
VALUE ret;
|
|
3402
|
-
struct
|
|
3403
|
-
|
|
3404
|
-
VALUE field = rb_ary_entry(args_ary, i);
|
|
3405
|
-
if (rb_obj_is_instance_of(field, cCurlPostField)) {
|
|
3406
|
-
append_to_form(field, &first, &last);
|
|
3407
|
-
} else if (rb_type(field) == T_ARRAY) {
|
|
3408
|
-
long j;
|
|
3409
|
-
for (j = 0; j < RARRAY_LEN(field); j++) {
|
|
3410
|
-
VALUE subfield = rb_ary_entry(field, j);
|
|
3411
|
-
if (rb_obj_is_instance_of(subfield, cCurlPostField)) {
|
|
3412
|
-
append_to_form(subfield, &first, &last);
|
|
3413
|
-
} else {
|
|
3414
|
-
rb_raise(eCurlErrInvalidPostField,
|
|
3415
|
-
"You must use PostFields only with multipart form posts");
|
|
3416
|
-
}
|
|
3417
|
-
}
|
|
3418
|
-
} else {
|
|
3419
|
-
rb_raise(eCurlErrInvalidPostField,
|
|
3420
|
-
"You must use PostFields only with multipart form posts");
|
|
3421
|
-
}
|
|
3422
|
-
}
|
|
3423
|
-
curl_easy_setopt(curl, CURLOPT_POST, 0);
|
|
3424
|
-
curl_easy_setopt(curl, CURLOPT_HTTPPOST, first);
|
|
3425
|
-
/* Set the method explicitly to PUT */
|
|
3426
|
-
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
|
|
3427
|
-
struct easy_form_perform_args perform_args = { curl, first };
|
|
3428
|
-
ret = rb_ensure(call_easy_perform, self, ensure_free_form_post, (VALUE)&perform_args);
|
|
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);
|
|
3429
3569
|
return ret;
|
|
3430
3570
|
}
|
|
3431
3571
|
/* Fallback: join all arguments */
|
|
@@ -3436,7 +3576,9 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
3436
3576
|
ruby_curl_easy_put_data_set(self, post_body);
|
|
3437
3577
|
}
|
|
3438
3578
|
}
|
|
3439
|
-
|
|
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);
|
|
3440
3582
|
}
|
|
3441
3583
|
|
|
3442
3584
|
|
|
@@ -4503,6 +4645,7 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
|
4503
4645
|
}
|
|
4504
4646
|
/* Save the list pointer in the ruby_curl_easy structure for cleanup later */
|
|
4505
4647
|
rbce->curl_resolve = list;
|
|
4648
|
+
rb_hash_aset(rbce->opts, rb_easy_hkey("resolve"), val);
|
|
4506
4649
|
curl_easy_setopt(rbce->curl, CURLOPT_RESOLVE, list);
|
|
4507
4650
|
} break;
|
|
4508
4651
|
#endif
|