curb 1.3.1 → 1.3.2
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 +171 -97
- data/ext/curb_postfield.c +1 -0
- data/tests/tc_curl_easy.rb +59 -0
- data/tests/tc_curl_native_coverage.rb +15 -0
- data/tests/tc_curl_postfield.rb +15 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3f62e867480076ceef877a4adcb5c3b4a344769207af06ded4535a3ce1e87375
|
|
4
|
+
data.tar.gz: 4caa926321d05804edbd4b0470951a617192ffd2504ac741524306edec1fe193
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 917f5e735b7187b5089896a83442462ed7f7b9311dbf616e58ab2cae3b2dff38e28f51f401e183214779d8f5159da6fa6dc7d842c0b5e21993cd428f61868d1f
|
|
7
|
+
data.tar.gz: 986d63577872fc80a563a4f2ac29a169888eb549d7ba462ecdef89636f3087be48ad7895e13954824e5af069614601ae30730a0af88cd4b3ad3391997b37c3e3
|
data/ext/curb.h
CHANGED
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
#include "curb_macros.h"
|
|
29
29
|
|
|
30
30
|
// These should be managed from the Rake 'release' task.
|
|
31
|
-
#define CURB_VERSION "1.3.
|
|
32
|
-
#define CURB_VER_NUM
|
|
31
|
+
#define CURB_VERSION "1.3.2"
|
|
32
|
+
#define CURB_VER_NUM 1032
|
|
33
33
|
#define CURB_VER_MAJ 1
|
|
34
34
|
#define CURB_VER_MIN 3
|
|
35
|
-
#define CURB_VER_MIC
|
|
35
|
+
#define CURB_VER_MIC 2
|
|
36
36
|
#define CURB_VER_PATCH 0
|
|
37
37
|
|
|
38
38
|
|
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>
|
|
@@ -763,6 +845,21 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
|
763
845
|
/* Set the error buffer on the new curl handle using the new err_buf */
|
|
764
846
|
curl_easy_setopt(newrbce->curl, CURLOPT_ERRORBUFFER, newrbce->err_buf);
|
|
765
847
|
|
|
848
|
+
if (newrbce->opts != Qnil) {
|
|
849
|
+
VALUE upload = rb_hash_aref(newrbce->opts, rb_easy_hkey("upload"));
|
|
850
|
+
if (!NIL_P(upload)) {
|
|
851
|
+
rb_hash_aset(newrbce->opts, rb_easy_hkey("upload"), duplicate_upload(upload));
|
|
852
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_READFUNCTION, (curl_read_callback)read_data_handler);
|
|
853
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_READDATA, newrbce);
|
|
854
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
855
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_SEEKFUNCTION, (curl_seek_callback)seek_data_handler);
|
|
856
|
+
#endif
|
|
857
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
858
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_SEEKDATA, newrbce);
|
|
859
|
+
#endif
|
|
860
|
+
}
|
|
861
|
+
}
|
|
862
|
+
|
|
766
863
|
VALUE clone = TypedData_Wrap_Struct(cCurlEasy, &ruby_curl_easy_data_type, newrbce);
|
|
767
864
|
newrbce->self = clone;
|
|
768
865
|
curl_easy_setopt(newrbce->curl, CURLOPT_PRIVATE, (void*)newrbce);
|
|
@@ -801,6 +898,8 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
|
801
898
|
ruby_curl_easy_zero(rbce);
|
|
802
899
|
rbce->self = self;
|
|
803
900
|
|
|
901
|
+
curl_easy_setopt(rbce->curl, CURLOPT_ERRORBUFFER, rbce->err_buf);
|
|
902
|
+
|
|
804
903
|
/* give the new curl handle a reference back to the ruby object */
|
|
805
904
|
ecode = curl_easy_setopt(rbce->curl, CURLOPT_PRIVATE, (void*)rbce);
|
|
806
905
|
if (ecode != CURLE_OK) {
|
|
@@ -3095,6 +3194,12 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
|
3095
3194
|
curl_easy_setopt(curl, CURLOPT_UPLOAD, 0);
|
|
3096
3195
|
curl_easy_setopt(curl, CURLOPT_READFUNCTION, NULL);
|
|
3097
3196
|
curl_easy_setopt(curl, CURLOPT_READDATA, NULL);
|
|
3197
|
+
#ifdef HAVE_CURLOPT_SEEKFUNCTION
|
|
3198
|
+
curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, NULL);
|
|
3199
|
+
#endif
|
|
3200
|
+
#ifdef HAVE_CURLOPT_SEEKDATA
|
|
3201
|
+
curl_easy_setopt(curl, CURLOPT_SEEKDATA, NULL);
|
|
3202
|
+
#endif
|
|
3098
3203
|
curl_easy_setopt(curl, CURLOPT_INFILESIZE, 0);
|
|
3099
3204
|
}
|
|
3100
3205
|
|
|
@@ -3173,19 +3278,68 @@ static VALUE call_easy_perform(VALUE self) {
|
|
|
3173
3278
|
}
|
|
3174
3279
|
|
|
3175
3280
|
struct easy_form_perform_args {
|
|
3281
|
+
VALUE self;
|
|
3176
3282
|
CURL *curl;
|
|
3283
|
+
int argc;
|
|
3284
|
+
VALUE *argv;
|
|
3177
3285
|
struct curl_httppost *first;
|
|
3286
|
+
struct curl_httppost *last;
|
|
3287
|
+
int clear_customrequest;
|
|
3288
|
+
int form_set_on_curl;
|
|
3178
3289
|
};
|
|
3179
3290
|
|
|
3291
|
+
static void append_multipart_form_argument(VALUE arg,
|
|
3292
|
+
struct curl_httppost **first,
|
|
3293
|
+
struct curl_httppost **last) {
|
|
3294
|
+
if (rb_obj_is_instance_of(arg, cCurlPostField)) {
|
|
3295
|
+
append_to_form(arg, first, last);
|
|
3296
|
+
} else if (rb_type(arg) == T_ARRAY) {
|
|
3297
|
+
long j, argv_len = RARRAY_LEN(arg);
|
|
3298
|
+
for (j = 0; j < argv_len; ++j) {
|
|
3299
|
+
VALUE field = rb_ary_entry(arg, j);
|
|
3300
|
+
if (rb_obj_is_instance_of(field, cCurlPostField)) {
|
|
3301
|
+
append_to_form(field, first, last);
|
|
3302
|
+
} else {
|
|
3303
|
+
rb_raise(eCurlErrInvalidPostField,
|
|
3304
|
+
"You must use PostFields only with multipart form posts");
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
} else {
|
|
3308
|
+
rb_raise(eCurlErrInvalidPostField,
|
|
3309
|
+
"You must use PostFields only with multipart form posts");
|
|
3310
|
+
}
|
|
3311
|
+
}
|
|
3312
|
+
|
|
3313
|
+
static VALUE build_and_perform_multipart_form(VALUE argp) {
|
|
3314
|
+
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
3315
|
+
int i;
|
|
3316
|
+
|
|
3317
|
+
for (i = 0; i < args->argc; i++) {
|
|
3318
|
+
append_multipart_form_argument(args->argv[i], &args->first, &args->last);
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
curl_easy_setopt(args->curl, CURLOPT_POST, 0);
|
|
3322
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, args->first);
|
|
3323
|
+
args->form_set_on_curl = 1;
|
|
3324
|
+
|
|
3325
|
+
return call_easy_perform(args->self);
|
|
3326
|
+
}
|
|
3327
|
+
|
|
3180
3328
|
static VALUE ensure_free_form_post(VALUE argp) {
|
|
3181
3329
|
struct easy_form_perform_args *args = (struct easy_form_perform_args *)argp;
|
|
3182
3330
|
if (args->curl) {
|
|
3183
|
-
|
|
3331
|
+
if (args->form_set_on_curl) {
|
|
3332
|
+
curl_easy_setopt(args->curl, CURLOPT_HTTPPOST, NULL);
|
|
3333
|
+
}
|
|
3334
|
+
if (args->clear_customrequest) {
|
|
3335
|
+
curl_easy_setopt(args->curl, CURLOPT_CUSTOMREQUEST, NULL);
|
|
3336
|
+
}
|
|
3184
3337
|
}
|
|
3185
3338
|
if (args->first) {
|
|
3186
3339
|
curl_formfree(args->first);
|
|
3187
3340
|
args->first = NULL;
|
|
3188
3341
|
}
|
|
3342
|
+
args->last = NULL;
|
|
3189
3343
|
return Qnil;
|
|
3190
3344
|
}
|
|
3191
3345
|
|
|
@@ -3216,7 +3370,6 @@ static VALUE ensure_free_form_post(VALUE argp) {
|
|
|
3216
3370
|
static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
3217
3371
|
ruby_curl_easy *rbce;
|
|
3218
3372
|
CURL *curl;
|
|
3219
|
-
int i;
|
|
3220
3373
|
VALUE args_ary;
|
|
3221
3374
|
|
|
3222
3375
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
@@ -3230,33 +3383,8 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
3230
3383
|
|
|
3231
3384
|
if (rbce->multipart_form_post) {
|
|
3232
3385
|
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);
|
|
3386
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 0, 0 };
|
|
3387
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
3260
3388
|
|
|
3261
3389
|
return ret;
|
|
3262
3390
|
} else {
|
|
@@ -3300,7 +3428,6 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
|
3300
3428
|
static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
3301
3429
|
ruby_curl_easy *rbce;
|
|
3302
3430
|
CURL *curl;
|
|
3303
|
-
int i;
|
|
3304
3431
|
VALUE args_ary;
|
|
3305
3432
|
|
|
3306
3433
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
@@ -3315,35 +3442,8 @@ static VALUE ruby_curl_easy_perform_patch(int argc, VALUE *argv, VALUE self) {
|
|
|
3315
3442
|
|
|
3316
3443
|
if (rbce->multipart_form_post) {
|
|
3317
3444
|
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);
|
|
3445
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
3446
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
3347
3447
|
return ret;
|
|
3348
3448
|
} else {
|
|
3349
3449
|
/* Join arguments into a raw PATCH body */
|
|
@@ -3376,7 +3476,6 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
3376
3476
|
ruby_curl_easy *rbce;
|
|
3377
3477
|
CURL *curl;
|
|
3378
3478
|
VALUE args_ary;
|
|
3379
|
-
int i;
|
|
3380
3479
|
|
|
3381
3480
|
rb_scan_args(argc, argv, "*", &args_ary);
|
|
3382
3481
|
TypedData_Get_Struct(self, ruby_curl_easy, &ruby_curl_easy_data_type, rbce);
|
|
@@ -3399,33 +3498,8 @@ static VALUE ruby_curl_easy_perform_put(int argc, VALUE *argv, VALUE self) {
|
|
|
3399
3498
|
/* Otherwise, if multipart_form_post is true, use multipart logic */
|
|
3400
3499
|
else if (rbce->multipart_form_post) {
|
|
3401
3500
|
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);
|
|
3501
|
+
struct easy_form_perform_args perform_args = { self, curl, argc, argv, NULL, NULL, 1, 0 };
|
|
3502
|
+
ret = rb_ensure(build_and_perform_multipart_form, (VALUE)&perform_args, ensure_free_form_post, (VALUE)&perform_args);
|
|
3429
3503
|
return ret;
|
|
3430
3504
|
}
|
|
3431
3505
|
/* Fallback: join all arguments */
|
data/ext/curb_postfield.c
CHANGED
|
@@ -183,6 +183,7 @@ static void curl_postfield_mark(void *ptr) {
|
|
|
183
183
|
rb_gc_mark(rbcpf->name);
|
|
184
184
|
rb_gc_mark(rbcpf->content);
|
|
185
185
|
rb_gc_mark(rbcpf->content_type);
|
|
186
|
+
rb_gc_mark(rbcpf->content_proc);
|
|
186
187
|
rb_gc_mark(rbcpf->local_file);
|
|
187
188
|
rb_gc_mark(rbcpf->remote_file);
|
|
188
189
|
rb_gc_mark(rbcpf->buffer_str);
|
data/tests/tc_curl_easy.rb
CHANGED
|
@@ -1301,6 +1301,24 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
1301
1301
|
assert_equal "POST\nfoo=bar", curl.body_str
|
|
1302
1302
|
end
|
|
1303
1303
|
|
|
1304
|
+
def test_multipart_patch_build_failure_restores_easy_request_state
|
|
1305
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1306
|
+
curl.multipart_form_post = true
|
|
1307
|
+
field = Curl::PostField.content('document_id', '5')
|
|
1308
|
+
|
|
1309
|
+
field.name = nil
|
|
1310
|
+
error = assert_raise(Curl::Err::InvalidPostFieldError) do
|
|
1311
|
+
# The first field allocates native multipart form state before the second field raises.
|
|
1312
|
+
curl.http_patch(Curl::PostField.content('keep', 'allocated'), field)
|
|
1313
|
+
end
|
|
1314
|
+
assert_match(/Cannot post unnamed field/, error.message)
|
|
1315
|
+
|
|
1316
|
+
curl.multipart_form_post = false
|
|
1317
|
+
curl.perform
|
|
1318
|
+
|
|
1319
|
+
assert_equal 'GET', curl.body_str
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1304
1322
|
def test_delete_remote
|
|
1305
1323
|
curl = Curl::Easy.new(TestServlet.url)
|
|
1306
1324
|
curl.http_delete
|
|
@@ -1358,6 +1376,35 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
1358
1376
|
assert_match(/message$/, curl.body_str)
|
|
1359
1377
|
end
|
|
1360
1378
|
|
|
1379
|
+
def test_put_data_read_exception_sets_result_and_releases_callback_state
|
|
1380
|
+
error_class = Class.new(StandardError)
|
|
1381
|
+
reader_class = Class.new do
|
|
1382
|
+
define_method(:read) do |_len|
|
|
1383
|
+
raise error_class, 'upload read failed'
|
|
1384
|
+
end
|
|
1385
|
+
|
|
1386
|
+
def seek(_offset, _whence = SEEK_SET)
|
|
1387
|
+
0
|
|
1388
|
+
end
|
|
1389
|
+
|
|
1390
|
+
def stat
|
|
1391
|
+
Struct.new(:size).new(1)
|
|
1392
|
+
end
|
|
1393
|
+
end
|
|
1394
|
+
|
|
1395
|
+
curl = Curl::Easy.new(TestServlet.url)
|
|
1396
|
+
curl.put_data = reader_class.new
|
|
1397
|
+
|
|
1398
|
+
error = assert_raise(error_class) { curl.perform }
|
|
1399
|
+
assert_equal 'upload read failed', error.message
|
|
1400
|
+
assert_not_equal 0, curl.last_result
|
|
1401
|
+
|
|
1402
|
+
curl.url = TestServlet.url
|
|
1403
|
+
curl.http_get
|
|
1404
|
+
|
|
1405
|
+
assert_equal 'GET', curl.body_str
|
|
1406
|
+
end
|
|
1407
|
+
|
|
1361
1408
|
# https://github.com/taf2/curb/issues/101
|
|
1362
1409
|
def test_put_data_null_bytes
|
|
1363
1410
|
curl = Curl::Easy.new(TestServlet.url)
|
|
@@ -1501,6 +1548,18 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
|
1501
1548
|
easy.http_get
|
|
1502
1549
|
end
|
|
1503
1550
|
|
|
1551
|
+
def test_easy_close_restores_error_buffer
|
|
1552
|
+
easy = Curl::Easy.new('http://127.0.0.1:1')
|
|
1553
|
+
assert_raise(Curl::Err::ConnectionFailedError) { easy.perform }
|
|
1554
|
+
assert_not_nil easy.last_error
|
|
1555
|
+
|
|
1556
|
+
easy.close
|
|
1557
|
+
easy.url = 'http://127.0.0.1:1'
|
|
1558
|
+
assert_raise(Curl::Err::ConnectionFailedError) { easy.perform }
|
|
1559
|
+
|
|
1560
|
+
assert_not_nil easy.last_error
|
|
1561
|
+
end
|
|
1562
|
+
|
|
1504
1563
|
def test_easy_reset
|
|
1505
1564
|
easy = Curl::Easy.new
|
|
1506
1565
|
easy.url = TestServlet.url + "?query=foo"
|
|
@@ -90,6 +90,21 @@ class TestCurbCurlNativeCoverage < Test::Unit::TestCase
|
|
|
90
90
|
easy.close if defined?(easy) && easy
|
|
91
91
|
end
|
|
92
92
|
|
|
93
|
+
def test_clone_rebinds_upload_callbacks_to_clone_state
|
|
94
|
+
easy = Curl::Easy.new(TestServlet.url)
|
|
95
|
+
easy.put_data = 'clone-data'
|
|
96
|
+
|
|
97
|
+
clone = easy.clone
|
|
98
|
+
easy.put_data = 'other-data'
|
|
99
|
+
|
|
100
|
+
clone.perform
|
|
101
|
+
|
|
102
|
+
assert_equal "PUT\nclone-data", clone.body_str
|
|
103
|
+
ensure
|
|
104
|
+
clone.close if defined?(clone) && clone
|
|
105
|
+
easy.close if defined?(easy) && easy
|
|
106
|
+
end
|
|
107
|
+
|
|
93
108
|
def test_native_accessors_round_trip
|
|
94
109
|
easy = Curl::Easy.new(TestServlet.url)
|
|
95
110
|
|
data/tests/tc_curl_postfield.rb
CHANGED
|
@@ -136,11 +136,26 @@ class TestCurbCurlPostfield < Test::Unit::TestCase
|
|
|
136
136
|
assert_equal "foo=FOOBAR", pf.to_s
|
|
137
137
|
end
|
|
138
138
|
|
|
139
|
+
def test_content_proc_survives_gc
|
|
140
|
+
pf = postfield_with_only_native_proc_reference
|
|
141
|
+
|
|
142
|
+
10.times do
|
|
143
|
+
GC.start(full_mark: true, immediate_sweep: true)
|
|
144
|
+
GC.compact if GC.respond_to?(:compact)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
assert_equal "foo=FOOBAR", pf.to_s
|
|
148
|
+
end
|
|
149
|
+
|
|
139
150
|
def test_to_s_04
|
|
140
151
|
pf = Curl::PostField.file('foo.file', 'bar.file')
|
|
141
152
|
assert_nothing_raised { pf.to_s }
|
|
142
153
|
#assert_raise(Curl::Err::InvalidPostFieldError) { pf.to_s }
|
|
143
154
|
end
|
|
155
|
+
|
|
156
|
+
def postfield_with_only_native_proc_reference
|
|
157
|
+
Curl::PostField.content('foo') { |field| field.name.upcase + "BAR" }
|
|
158
|
+
end
|
|
144
159
|
end
|
|
145
160
|
|
|
146
161
|
class TestCurbCurlPostfieldNativeCoverage < Test::Unit::TestCase
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: curb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.3.
|
|
4
|
+
version: 1.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ross Bamford
|
|
8
8
|
- Todd A. Fisher
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-23 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings
|
|
14
14
|
for the libcurl(3), a fully-featured client-side URL transfer library. cURL and
|