curb 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +13 -0
- data/ext/curb.c +4 -0
- data/ext/curb.h +3 -3
- data/ext/curb_easy.c +99 -108
- data/ext/curb_easy.h +2 -0
- data/ext/curb_multi.c +12 -0
- data/ext/extconf.rb +3 -0
- data/lib/curb.rb +1 -0
- data/lib/curl.rb +56 -0
- data/lib/curl/easy.rb +83 -0
- data/lib/curl/multi.rb +8 -4
- data/tests/bug_issue102.rb +17 -0
- data/tests/foo.rb +13 -0
- data/tests/helper.rb +13 -5
- data/tests/tc_curl.rb +39 -0
- data/tests/tc_curl_easy.rb +14 -0
- data/tests/tc_curl_multi.rb +20 -1
- metadata +45 -25
data/README
CHANGED
@@ -56,6 +56,19 @@ Curb provides two classes:
|
|
56
56
|
+ Curl::Easy - simple API, for day-to-day tasks.
|
57
57
|
+ Curl::Multi - more advanced API, for operating on multiple URLs simultaneously.
|
58
58
|
|
59
|
+
### Super simple API (less typing)
|
60
|
+
|
61
|
+
http = Curl.get("http://www.google.com/")
|
62
|
+
puts http.body_str
|
63
|
+
|
64
|
+
http = Curl.post("http://www.google.com/", {:foo => "bar"})
|
65
|
+
puts http.body_str
|
66
|
+
|
67
|
+
http = Curl.get("http://www.google.com/") do|http|
|
68
|
+
http.headers['Cookie'] = 'foo=1;bar=2'
|
69
|
+
end
|
70
|
+
puts http.body_str
|
71
|
+
|
59
72
|
### Simple fetch via HTTP:
|
60
73
|
|
61
74
|
c = Curl::Easy.perform("http://www.google.co.uk")
|
data/ext/curb.c
CHANGED
@@ -424,8 +424,12 @@ void Init_curb_core() {
|
|
424
424
|
CURB_DEFINE(CURLOPT_FAILONERROR);
|
425
425
|
#endif
|
426
426
|
CURB_DEFINE(CURLOPT_URL);
|
427
|
+
#if HAVE_CURLOPT_PROTOCOLS
|
427
428
|
CURB_DEFINE(CURLOPT_PROTOCOLS);
|
429
|
+
#endif
|
430
|
+
#if HAVE_CURLOPT_REDIR_PROTOCOLS
|
428
431
|
CURB_DEFINE(CURLOPT_REDIR_PROTOCOLS);
|
432
|
+
#endif
|
429
433
|
CURB_DEFINE(CURLOPT_PROXY);
|
430
434
|
CURB_DEFINE(CURLOPT_PROXYPORT);
|
431
435
|
#if HAVE_CURLOPT_PROXYTYPE
|
data/ext/curb.h
CHANGED
@@ -20,11 +20,11 @@
|
|
20
20
|
#include "curb_macros.h"
|
21
21
|
|
22
22
|
// These should be managed from the Rake 'release' task.
|
23
|
-
#define CURB_VERSION "0.8.
|
24
|
-
#define CURB_VER_NUM
|
23
|
+
#define CURB_VERSION "0.8.1"
|
24
|
+
#define CURB_VER_NUM 801
|
25
25
|
#define CURB_VER_MAJ 0
|
26
26
|
#define CURB_VER_MIN 8
|
27
|
-
#define CURB_VER_MIC
|
27
|
+
#define CURB_VER_MIC 1
|
28
28
|
#define CURB_VER_PATCH 0
|
29
29
|
|
30
30
|
|
data/ext/curb_easy.c
CHANGED
@@ -115,6 +115,30 @@ static size_t proc_data_handler(char *stream,
|
|
115
115
|
}
|
116
116
|
}
|
117
117
|
|
118
|
+
static size_t proc_data_handler_body(char *stream,
|
119
|
+
size_t size,
|
120
|
+
size_t nmemb,
|
121
|
+
ruby_curl_easy *rbce)
|
122
|
+
{
|
123
|
+
size_t ret;
|
124
|
+
rbce->callback_active = 1;
|
125
|
+
ret = proc_data_handler(stream, size, nmemb, rb_easy_get("body_proc"));
|
126
|
+
rbce->callback_active = 0;
|
127
|
+
return ret;
|
128
|
+
}
|
129
|
+
static size_t proc_data_handler_header(char *stream,
|
130
|
+
size_t size,
|
131
|
+
size_t nmemb,
|
132
|
+
ruby_curl_easy *rbce)
|
133
|
+
{
|
134
|
+
size_t ret;
|
135
|
+
rbce->callback_active = 1;
|
136
|
+
ret = proc_data_handler(stream, size, nmemb, rb_easy_get("header_proc"));
|
137
|
+
rbce->callback_active = 0;
|
138
|
+
return ret;
|
139
|
+
}
|
140
|
+
|
141
|
+
|
118
142
|
static VALUE call_progress_handler(VALUE ary) {
|
119
143
|
return rb_funcall(rb_ary_entry(ary, 0), idCall, 4,
|
120
144
|
rb_ary_entry(ary, 1), // rb_float_new(dltotal),
|
@@ -157,13 +181,14 @@ static int proc_debug_handler(CURL *curl,
|
|
157
181
|
char *data,
|
158
182
|
size_t data_len,
|
159
183
|
VALUE proc) {
|
160
|
-
VALUE procret;
|
161
184
|
VALUE callargs = rb_ary_new2(3);
|
162
185
|
rb_ary_store(callargs, 0, proc);
|
163
186
|
rb_ary_store(callargs, 1, INT2FIX(type));
|
164
187
|
rb_ary_store(callargs, 2, rb_str_new(data, data_len));
|
165
188
|
rb_rescue(call_debug_handler, callargs, callback_exception, Qnil);
|
166
|
-
|
189
|
+
/* no way to indicate to libcurl that we should break out given an exception in the on_debug handler...
|
190
|
+
* this means exceptions will be swallowed
|
191
|
+
*/
|
167
192
|
//rb_funcall(proc, idCall, 2, INT2FIX(type), rb_str_new(data, data_len));
|
168
193
|
return 0;
|
169
194
|
}
|
@@ -234,6 +259,7 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
|
234
259
|
rbce->multipart_form_post = 0;
|
235
260
|
rbce->enable_cookies = 0;
|
236
261
|
rbce->ignore_content_length = 0;
|
262
|
+
rbce->callback_active = 0;
|
237
263
|
}
|
238
264
|
|
239
265
|
/*
|
@@ -320,6 +346,10 @@ static VALUE ruby_curl_easy_close(VALUE self) {
|
|
320
346
|
|
321
347
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
322
348
|
|
349
|
+
if (rbce->callback_active) {
|
350
|
+
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
351
|
+
}
|
352
|
+
|
323
353
|
ruby_curl_easy_free(rbce);
|
324
354
|
|
325
355
|
/* reinit the handle */
|
@@ -358,6 +388,11 @@ static VALUE ruby_curl_easy_reset(VALUE self) {
|
|
358
388
|
ruby_curl_easy *rbce;
|
359
389
|
VALUE opts_dup;
|
360
390
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
391
|
+
|
392
|
+
if (rbce->callback_active) {
|
393
|
+
rb_raise(rb_eRuntimeError, "Cannot close an active curl handle within a callback");
|
394
|
+
}
|
395
|
+
|
361
396
|
opts_dup = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
362
397
|
|
363
398
|
curl_easy_reset(rbce->curl);
|
@@ -1443,17 +1478,6 @@ static VALUE ruby_curl_easy_use_netrc_q(VALUE self) {
|
|
1443
1478
|
CURB_BOOLEAN_GETTER(ruby_curl_easy, use_netrc);
|
1444
1479
|
}
|
1445
1480
|
|
1446
|
-
/*
|
1447
|
-
* call-seq:
|
1448
|
-
* easy.follow_location = boolean => boolean
|
1449
|
-
*
|
1450
|
-
* Configure whether this Curl instance will follow Location: headers
|
1451
|
-
* in HTTP responses. Redirects will only be followed to the extent
|
1452
|
-
* specified by +max_redirects+.
|
1453
|
-
*/
|
1454
|
-
static VALUE ruby_curl_easy_follow_location_set(VALUE self, VALUE follow_location) {
|
1455
|
-
CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
|
1456
|
-
}
|
1457
1481
|
/*
|
1458
1482
|
* call-seq:
|
1459
1483
|
*
|
@@ -1872,7 +1896,7 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap) {
|
|
1872
1896
|
*
|
1873
1897
|
* Always returns Qtrue, rb_raise on error.
|
1874
1898
|
*/
|
1875
|
-
VALUE ruby_curl_easy_setup(
|
1899
|
+
VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
|
1876
1900
|
// TODO this could do with a bit of refactoring...
|
1877
1901
|
CURL *curl;
|
1878
1902
|
VALUE url, _url = rb_easy_get("url");
|
@@ -1934,8 +1958,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
|
|
1934
1958
|
|
1935
1959
|
// body/header procs
|
1936
1960
|
if (!rb_easy_nil("body_proc")) {
|
1937
|
-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&
|
1938
|
-
curl_easy_setopt(curl, CURLOPT_WRITEDATA,
|
1961
|
+
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
|
1962
|
+
curl_easy_setopt(curl, CURLOPT_WRITEDATA, rbce);
|
1939
1963
|
/* clear out the body_data if it was set */
|
1940
1964
|
rb_easy_del("body_data");
|
1941
1965
|
} else {
|
@@ -1945,8 +1969,8 @@ VALUE ruby_curl_easy_setup( ruby_curl_easy *rbce ) {
|
|
1945
1969
|
}
|
1946
1970
|
|
1947
1971
|
if (!rb_easy_nil("header_proc")) {
|
1948
|
-
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&
|
1949
|
-
curl_easy_setopt(curl, CURLOPT_HEADERDATA,
|
1972
|
+
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, (curl_write_callback)&proc_data_handler_header);
|
1973
|
+
curl_easy_setopt(curl, CURLOPT_HEADERDATA, rbce);
|
1950
1974
|
/* clear out the header_data if it was set */
|
1951
1975
|
rb_easy_del("header_data");
|
1952
1976
|
} else {
|
@@ -2202,27 +2226,6 @@ VALUE ruby_curl_easy_cleanup( VALUE self, ruby_curl_easy *rbce ) {
|
|
2202
2226
|
return Qnil;
|
2203
2227
|
}
|
2204
2228
|
|
2205
|
-
/*
|
2206
|
-
* call-seq:
|
2207
|
-
* easy.http_get => true
|
2208
|
-
*
|
2209
|
-
* GET the currently configured URL using the current options set for
|
2210
|
-
* this Curl::Easy instance. This method always returns true, or raises
|
2211
|
-
* an exception (defined under Curl::Err) on error.
|
2212
|
-
*/
|
2213
|
-
static VALUE ruby_curl_easy_perform_get(VALUE self) {
|
2214
|
-
ruby_curl_easy *rbce;
|
2215
|
-
CURL *curl;
|
2216
|
-
|
2217
|
-
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2218
|
-
curl = rbce->curl;
|
2219
|
-
|
2220
|
-
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2221
|
-
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
2222
|
-
|
2223
|
-
return rb_funcall(self, rb_intern("perform"), 0);
|
2224
|
-
}
|
2225
|
-
|
2226
2229
|
/*
|
2227
2230
|
* Common implementation of easy.http(verb) and easy.http_delete
|
2228
2231
|
*/
|
@@ -2243,18 +2246,6 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
2243
2246
|
return retval;
|
2244
2247
|
}
|
2245
2248
|
|
2246
|
-
/*
|
2247
|
-
* call-seq:
|
2248
|
-
* easy.http_delete
|
2249
|
-
*
|
2250
|
-
* DELETE the currently configured URL using the current options set for
|
2251
|
-
* this Curl::Easy instance. This method always returns true, or raises
|
2252
|
-
* an exception (defined under Curl::Err) on error.
|
2253
|
-
*/
|
2254
|
-
static VALUE ruby_curl_easy_perform_delete(VALUE self) {
|
2255
|
-
return ruby_curl_easy_perform_verb_str(self, "DELETE");
|
2256
|
-
}
|
2257
|
-
|
2258
2249
|
/*
|
2259
2250
|
* call-seq:
|
2260
2251
|
* easy.http(verb)
|
@@ -2367,52 +2358,6 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2367
2358
|
}
|
2368
2359
|
}
|
2369
2360
|
|
2370
|
-
/*
|
2371
|
-
* call-seq:
|
2372
|
-
* easy.http_head => true
|
2373
|
-
*
|
2374
|
-
* Request headers from the currently configured URL using the HEAD
|
2375
|
-
* method and current options set for this Curl::Easy instance. This
|
2376
|
-
* method always returns true, or raises an exception (defined under
|
2377
|
-
* Curl::Err) on error.
|
2378
|
-
*
|
2379
|
-
*/
|
2380
|
-
static VALUE ruby_curl_easy_perform_head(VALUE self) {
|
2381
|
-
ruby_curl_easy *rbce;
|
2382
|
-
CURL *curl;
|
2383
|
-
VALUE ret;
|
2384
|
-
|
2385
|
-
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2386
|
-
curl = rbce->curl;
|
2387
|
-
|
2388
|
-
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
|
2389
|
-
|
2390
|
-
ret = rb_funcall(self, rb_intern("perform"), 0);
|
2391
|
-
|
2392
|
-
curl_easy_setopt(curl, CURLOPT_NOBODY, 0);
|
2393
|
-
return ret;
|
2394
|
-
}
|
2395
|
-
|
2396
|
-
/*
|
2397
|
-
*call-seq:
|
2398
|
-
* easy = Curl::Easy.new("url") do|c|
|
2399
|
-
* c.head = true
|
2400
|
-
* end
|
2401
|
-
* easy.perform
|
2402
|
-
*/
|
2403
|
-
static VALUE ruby_curl_easy_set_head_option(VALUE self, VALUE onoff) {
|
2404
|
-
ruby_curl_easy *rbce;
|
2405
|
-
|
2406
|
-
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2407
|
-
|
2408
|
-
if (onoff == Qtrue) {
|
2409
|
-
curl_easy_setopt(rbce->curl, CURLOPT_NOBODY, 1);
|
2410
|
-
} else {
|
2411
|
-
curl_easy_setopt(rbce->curl, CURLOPT_NOBODY, 0);
|
2412
|
-
}
|
2413
|
-
|
2414
|
-
return onoff;
|
2415
|
-
}
|
2416
2361
|
/*
|
2417
2362
|
* call-seq:
|
2418
2363
|
* easy.http_put(data) => true
|
@@ -2720,6 +2665,36 @@ static VALUE ruby_curl_easy_redirect_count_get(VALUE self) {
|
|
2720
2665
|
|
2721
2666
|
}
|
2722
2667
|
|
2668
|
+
/*
|
2669
|
+
* call-seq:
|
2670
|
+
* easy.redirect_url => "http://some.url" or nil
|
2671
|
+
*
|
2672
|
+
* Retrieve the URL a redirect would take you to if you
|
2673
|
+
* would enable CURLOPT_FOLLOWLOCATION.
|
2674
|
+
*
|
2675
|
+
* Requires libcurl 7.18.2 or higher, otherwise -1 is always returned.
|
2676
|
+
*/
|
2677
|
+
static VALUE ruby_curl_easy_redirect_url_get(VALUE self) {
|
2678
|
+
#ifdef HAVE_CURLINFO_REDIRECT_URL
|
2679
|
+
ruby_curl_easy *rbce;
|
2680
|
+
char* url;
|
2681
|
+
|
2682
|
+
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2683
|
+
curl_easy_getinfo(rbce->curl, CURLINFO_REDIRECT_URL, &url);
|
2684
|
+
|
2685
|
+
if (url && url[0]) { // curl returns empty string if none
|
2686
|
+
return rb_str_new2(url);
|
2687
|
+
} else {
|
2688
|
+
return Qnil;
|
2689
|
+
}
|
2690
|
+
#else
|
2691
|
+
rb_warn("Installed libcurl is too old to support redirect_url");
|
2692
|
+
return INT2FIX(-1);
|
2693
|
+
#endif
|
2694
|
+
}
|
2695
|
+
|
2696
|
+
|
2697
|
+
|
2723
2698
|
/*
|
2724
2699
|
* call-seq:
|
2725
2700
|
* easy.uploaded_bytes => float
|
@@ -3070,11 +3045,10 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3070
3045
|
VALUE verbose = val;
|
3071
3046
|
CURB_BOOLEAN_SETTER(ruby_curl_easy, verbose);
|
3072
3047
|
} break;
|
3073
|
-
case
|
3074
|
-
|
3075
|
-
|
3076
|
-
|
3077
|
-
break;
|
3048
|
+
case CURLOPT_FOLLOWLOCATION: {
|
3049
|
+
VALUE follow_location = val;
|
3050
|
+
CURB_BOOLEAN_SETTER(ruby_curl_easy, follow_location);
|
3051
|
+
} break;
|
3078
3052
|
/* TODO: CALLBACK OPTIONS */
|
3079
3053
|
/* TODO: ERROR OPTIONS */
|
3080
3054
|
/* NETWORK OPTIONS */
|
@@ -3096,6 +3070,22 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3096
3070
|
VALUE interface_hm = val;
|
3097
3071
|
CURB_OBJECT_HSETTER(ruby_curl_easy, interface_hm);
|
3098
3072
|
} break;
|
3073
|
+
case CURLOPT_HEADER:
|
3074
|
+
case CURLOPT_NOPROGRESS:
|
3075
|
+
case CURLOPT_NOSIGNAL:
|
3076
|
+
case CURLOPT_HTTPGET:
|
3077
|
+
case CURLOPT_NOBODY: {
|
3078
|
+
int type = rb_type(val);
|
3079
|
+
VALUE value;
|
3080
|
+
if (type == T_TRUE) {
|
3081
|
+
value = rb_int_new(1);
|
3082
|
+
} else if (type == T_FALSE) {
|
3083
|
+
value = rb_int_new(0);
|
3084
|
+
} else {
|
3085
|
+
value = rb_funcall(val, rb_intern("to_i"), 0);
|
3086
|
+
}
|
3087
|
+
curl_easy_setopt(rbce->curl, option, FIX2INT(value));
|
3088
|
+
} break;
|
3099
3089
|
case CURLOPT_USERPWD: {
|
3100
3090
|
VALUE userpwd = val;
|
3101
3091
|
CURB_OBJECT_HSETTER(ruby_curl_easy, userpwd);
|
@@ -3116,7 +3106,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3116
3106
|
VALUE cookiejar = val;
|
3117
3107
|
CURB_OBJECT_HSETTER(ruby_curl_easy, cookiejar);
|
3118
3108
|
} break;
|
3119
|
-
|
3109
|
+
case CURLOPT_RESUME_FROM: {
|
3110
|
+
curl_easy_setopt(rbce->curl, CURLOPT_RESUME_FROM, FIX2LONG(val));
|
3111
|
+
} break;
|
3112
|
+
case CURLOPT_FAILONERROR: {
|
3113
|
+
curl_easy_setopt(rbce->curl, CURLOPT_FAILONERROR, FIX2LONG(val));
|
3114
|
+
} break;
|
3120
3115
|
default:
|
3121
3116
|
break;
|
3122
3117
|
}
|
@@ -3326,7 +3321,6 @@ void init_curb_easy() {
|
|
3326
3321
|
rb_define_method(cCurlEasy, "header_in_body?", ruby_curl_easy_header_in_body_q, 0);
|
3327
3322
|
rb_define_method(cCurlEasy, "use_netrc=", ruby_curl_easy_use_netrc_set, 1);
|
3328
3323
|
rb_define_method(cCurlEasy, "use_netrc?", ruby_curl_easy_use_netrc_q, 0);
|
3329
|
-
rb_define_method(cCurlEasy, "follow_location=", ruby_curl_easy_follow_location_set, 1);
|
3330
3324
|
rb_define_method(cCurlEasy, "follow_location?", ruby_curl_easy_follow_location_q, 0);
|
3331
3325
|
rb_define_method(cCurlEasy, "autoreferer=", ruby_curl_easy_autoreferer_set, 1);
|
3332
3326
|
rb_define_method(cCurlEasy, "unrestricted_auth=", ruby_curl_easy_unrestricted_auth_set, 1);
|
@@ -3353,12 +3347,8 @@ void init_curb_easy() {
|
|
3353
3347
|
rb_define_method(cCurlEasy, "on_complete", ruby_curl_easy_on_complete_set, -1);
|
3354
3348
|
|
3355
3349
|
rb_define_method(cCurlEasy, "http", ruby_curl_easy_perform_verb, 1);
|
3356
|
-
rb_define_method(cCurlEasy, "http_delete", ruby_curl_easy_perform_delete, 0);
|
3357
|
-
rb_define_method(cCurlEasy, "http_get", ruby_curl_easy_perform_get, 0);
|
3358
3350
|
rb_define_method(cCurlEasy, "http_post", ruby_curl_easy_perform_post, -1);
|
3359
|
-
rb_define_method(cCurlEasy, "http_head", ruby_curl_easy_perform_head, 0);
|
3360
3351
|
rb_define_method(cCurlEasy, "http_put", ruby_curl_easy_perform_put, 1);
|
3361
|
-
rb_define_method(cCurlEasy, "head=", ruby_curl_easy_set_head_option, 1);
|
3362
3352
|
|
3363
3353
|
/* Post-perform info methods */
|
3364
3354
|
rb_define_method(cCurlEasy, "body_str", ruby_curl_easy_body_str_get, 0);
|
@@ -3378,6 +3368,7 @@ void init_curb_easy() {
|
|
3378
3368
|
rb_define_method(cCurlEasy, "start_transfer_time", ruby_curl_easy_start_transfer_time_get, 0);
|
3379
3369
|
rb_define_method(cCurlEasy, "redirect_time", ruby_curl_easy_redirect_time_get, 0);
|
3380
3370
|
rb_define_method(cCurlEasy, "redirect_count", ruby_curl_easy_redirect_count_get, 0);
|
3371
|
+
rb_define_method(cCurlEasy, "redirect_url", ruby_curl_easy_redirect_url_get, 0);
|
3381
3372
|
rb_define_method(cCurlEasy, "downloaded_bytes", ruby_curl_easy_downloaded_bytes_get, 0);
|
3382
3373
|
rb_define_method(cCurlEasy, "uploaded_bytes", ruby_curl_easy_uploaded_bytes_get, 0);
|
3383
3374
|
rb_define_method(cCurlEasy, "download_speed", ruby_curl_easy_download_speed_get, 0);
|
data/ext/curb_easy.h
CHANGED
data/ext/curb_multi.c
CHANGED
@@ -354,7 +354,9 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
354
354
|
|
355
355
|
if (!rb_easy_nil("complete_proc")) {
|
356
356
|
callargs = rb_ary_new3(2, rb_easy_get("complete_proc"), easy);
|
357
|
+
rbce->callback_active = 1;
|
357
358
|
val = rb_rescue(call_status_handler1, callargs, callback_exception, Qnil);
|
359
|
+
rbce->callback_active = 0;
|
358
360
|
//rb_funcall( rb_easy_get("complete_proc"), idCall, 1, easy );
|
359
361
|
}
|
360
362
|
|
@@ -363,7 +365,9 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
363
365
|
if (result != 0) {
|
364
366
|
if (!rb_easy_nil("failure_proc")) {
|
365
367
|
callargs = rb_ary_new3(3, rb_easy_get("failure_proc"), easy, rb_curl_easy_error(result));
|
368
|
+
rbce->callback_active = 1;
|
366
369
|
val = rb_rescue(call_status_handler2, callargs, callback_exception, Qnil);
|
370
|
+
rbce->callback_active = 0;
|
367
371
|
//rb_funcall( rb_easy_get("failure_proc"), idCall, 2, easy, rb_curl_easy_error(result) );
|
368
372
|
}
|
369
373
|
}
|
@@ -371,23 +375,31 @@ static void rb_curl_mutli_handle_complete(VALUE self, CURL *easy_handle, int res
|
|
371
375
|
((response_code >= 200 && response_code < 300) || response_code == 0)) {
|
372
376
|
/* NOTE: we allow response_code == 0, in the case of non http requests e.g. reading from disk */
|
373
377
|
callargs = rb_ary_new3(2, rb_easy_get("success_proc"), easy);
|
378
|
+
rbce->callback_active = 1;
|
374
379
|
val = rb_rescue(call_status_handler1, callargs, callback_exception, Qnil);
|
380
|
+
rbce->callback_active = 0;
|
375
381
|
//rb_funcall( rb_easy_get("success_proc"), idCall, 1, easy );
|
376
382
|
}
|
377
383
|
else if (!rb_easy_nil("redirect_proc") &&
|
378
384
|
(response_code >= 300 && response_code < 400)) {
|
385
|
+
rbce->callback_active = 1;
|
379
386
|
callargs = rb_ary_new3(3, rb_easy_get("redirect_proc"), easy, rb_curl_easy_error(result));
|
387
|
+
rbce->callback_active = 0;
|
380
388
|
val = rb_rescue(call_status_handler2, callargs, callback_exception, Qnil);
|
381
389
|
}
|
382
390
|
else if (!rb_easy_nil("missing_proc") &&
|
383
391
|
(response_code >= 400 && response_code < 500)) {
|
392
|
+
rbce->callback_active = 1;
|
384
393
|
callargs = rb_ary_new3(3, rb_easy_get("missing_proc"), easy, rb_curl_easy_error(result));
|
394
|
+
rbce->callback_active = 0;
|
385
395
|
val = rb_rescue(call_status_handler2, callargs, callback_exception, Qnil);
|
386
396
|
}
|
387
397
|
else if (!rb_easy_nil("failure_proc") &&
|
388
398
|
(response_code >= 500 && response_code <= 999)) {
|
389
399
|
callargs = rb_ary_new3(3, rb_easy_get("failure_proc"), easy, rb_curl_easy_error(result));
|
400
|
+
rbce->callback_active = 1;
|
390
401
|
val = rb_rescue(call_status_handler2, callargs, callback_exception, Qnil);
|
402
|
+
rbce->callback_active = 0;
|
391
403
|
//rb_funcall( rb_easy_get("failure_proc"), idCall, 2, easy, rb_curl_easy_error(result) );
|
392
404
|
}
|
393
405
|
|
data/ext/extconf.rb
CHANGED
@@ -119,6 +119,9 @@ have_constant "curle_again"
|
|
119
119
|
have_constant "curle_ssl_crl_badfile"
|
120
120
|
have_constant "curle_ssl_issuer_error"
|
121
121
|
|
122
|
+
# added in 7.18.2
|
123
|
+
have_constant "curlinfo_redirect_url"
|
124
|
+
|
122
125
|
# username/password added in 7.19.1
|
123
126
|
have_constant "curlopt_username"
|
124
127
|
have_constant "curlopt_password"
|
data/lib/curb.rb
CHANGED
data/lib/curl.rb
CHANGED
@@ -1 +1,57 @@
|
|
1
1
|
require 'curb'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
# expose shortcut methods
|
5
|
+
module Curl
|
6
|
+
|
7
|
+
def self.http(verb, url, post_body=nil, put_data=nil, &block)
|
8
|
+
handle = Curl::Easy.new(url)
|
9
|
+
handle.post_body = post_body if post_body
|
10
|
+
handle.put_data = put_data if put_data
|
11
|
+
yield handle if block_given?
|
12
|
+
handle.http(verb)
|
13
|
+
handle
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.get(url, params={}, &block)
|
17
|
+
http :GET, urlalize(url, params), nil, nil, &block
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.post(url, params={}, &block)
|
21
|
+
http :POST, url, postalize(params), nil, &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.put(url, params={}, &block)
|
25
|
+
http :PUT, url, nil, postalize(params), &block
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.delete(url, params={}, &block)
|
29
|
+
http :DELETE, url, postalize(params), nil, &block
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.patch(url, params={}, &block)
|
33
|
+
http :PATCH, url, postalize(params), nil, &block
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.head(url, params={}, &block)
|
37
|
+
http :OPTIONS, urlalize(url, params), nil, nil, &block
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.options(url, params={}, &block)
|
41
|
+
http :OPTIONS, urlalize(url, params), nil, nil, &block
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.urlalize(url, params={})
|
45
|
+
query_str = params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
|
46
|
+
if url.match(/\?/)
|
47
|
+
"#{url}&#{query_str}"
|
48
|
+
else
|
49
|
+
"#{url}?#{query_str}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.postalize(params={})
|
54
|
+
params.map {|k,v| "#{URI.escape(k.to_s)}=#{URI.escape(v.to_s)}" }.join('&')
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/lib/curl/easy.rb
CHANGED
@@ -1,6 +1,23 @@
|
|
1
1
|
module Curl
|
2
2
|
class Easy
|
3
3
|
|
4
|
+
alias post http_post
|
5
|
+
alias put http_put
|
6
|
+
|
7
|
+
#
|
8
|
+
# call-seq:
|
9
|
+
# easy.status => String
|
10
|
+
#
|
11
|
+
def status
|
12
|
+
parts = self.header_str.split(/\s/)
|
13
|
+
status = []
|
14
|
+
parts.shift
|
15
|
+
while parts.size > 0 && parts.first != ''
|
16
|
+
status << parts.shift
|
17
|
+
end
|
18
|
+
status.join(' ')
|
19
|
+
end
|
20
|
+
|
4
21
|
#
|
5
22
|
# call-seq:
|
6
23
|
# easy.set :sym|Fixnum, value
|
@@ -213,6 +230,72 @@ module Curl
|
|
213
230
|
set :cookiejar, value
|
214
231
|
end
|
215
232
|
|
233
|
+
#
|
234
|
+
# call-seq:
|
235
|
+
# easy = Curl::Easy.new("url") do|c|
|
236
|
+
# c.head = true
|
237
|
+
# end
|
238
|
+
# easy.perform
|
239
|
+
#
|
240
|
+
def head=(onoff)
|
241
|
+
set :nobody, onoff
|
242
|
+
end
|
243
|
+
|
244
|
+
#
|
245
|
+
# call-seq:
|
246
|
+
# easy.follow_location = boolean => boolean
|
247
|
+
#
|
248
|
+
# Configure whether this Curl instance will follow Location: headers
|
249
|
+
# in HTTP responses. Redirects will only be followed to the extent
|
250
|
+
# specified by +max_redirects+.
|
251
|
+
#
|
252
|
+
def follow_location=(onoff)
|
253
|
+
set :followlocation, onoff
|
254
|
+
end
|
255
|
+
|
256
|
+
#
|
257
|
+
# call-seq:
|
258
|
+
# easy.http_head => true
|
259
|
+
#
|
260
|
+
# Request headers from the currently configured URL using the HEAD
|
261
|
+
# method and current options set for this Curl::Easy instance. This
|
262
|
+
# method always returns true, or raises an exception (defined under
|
263
|
+
# Curl::Err) on error.
|
264
|
+
#
|
265
|
+
def http_head
|
266
|
+
set :nobody, true
|
267
|
+
ret = self.perform
|
268
|
+
set :nobody, false
|
269
|
+
ret
|
270
|
+
end
|
271
|
+
|
272
|
+
#
|
273
|
+
# call-seq:
|
274
|
+
# easy.http_get => true
|
275
|
+
#
|
276
|
+
# GET the currently configured URL using the current options set for
|
277
|
+
# this Curl::Easy instance. This method always returns true, or raises
|
278
|
+
# an exception (defined under Curl::Err) on error.
|
279
|
+
#
|
280
|
+
def http_get
|
281
|
+
set :httpget, true
|
282
|
+
http :GET
|
283
|
+
end
|
284
|
+
alias get http_get
|
285
|
+
|
286
|
+
#
|
287
|
+
# call-seq:
|
288
|
+
# easy.http_delete
|
289
|
+
#
|
290
|
+
# DELETE the currently configured URL using the current options set for
|
291
|
+
# this Curl::Easy instance. This method always returns true, or raises
|
292
|
+
# an exception (defined under Curl::Err) on error.
|
293
|
+
#
|
294
|
+
def http_delete
|
295
|
+
self.http :DELETE
|
296
|
+
end
|
297
|
+
alias delete http_delete
|
298
|
+
|
216
299
|
class << self
|
217
300
|
|
218
301
|
#
|
data/lib/curl/multi.rb
CHANGED
@@ -157,13 +157,17 @@ module Curl
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
-
|
161
|
-
m.perform
|
160
|
+
if urls_with_config.empty?
|
161
|
+
m.perform
|
162
|
+
else
|
163
|
+
until urls_with_config.empty?
|
164
|
+
m.perform do
|
165
|
+
consume_free_handles.call
|
166
|
+
end
|
162
167
|
consume_free_handles.call
|
163
168
|
end
|
164
|
-
|
169
|
+
free_handles = nil
|
165
170
|
end
|
166
|
-
free_handles = nil
|
167
171
|
end
|
168
172
|
|
169
173
|
# call-seq:
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
+
|
3
|
+
class BugIssue102 < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_interface
|
6
|
+
test = "https://api.twitter.com/1/users/show.json?screen_name=TwitterAPI&include_entities=true"
|
7
|
+
ip = "192.168.1.61"
|
8
|
+
|
9
|
+
c = Curl::Easy.new do |curl|
|
10
|
+
curl.url = test
|
11
|
+
curl.interface = ip
|
12
|
+
end
|
13
|
+
|
14
|
+
c.perform
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/tests/foo.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'curb'
|
2
|
+
|
3
|
+
SSL_CERT = '/path/to/my/cert'
|
4
|
+
SSL_KEY = '/path/to/my/key'
|
5
|
+
|
6
|
+
curl = Curl::Easy.new('98.129.21.125')
|
7
|
+
curl.verbose = true
|
8
|
+
curl.cert = SSL_CERT
|
9
|
+
curl.cert_key = SSL_KEY
|
10
|
+
curl.follow_location = true
|
11
|
+
curl.ssl_verify_host = false
|
12
|
+
curl.ssl_verify_peer = false
|
13
|
+
curl.perform
|
data/tests/helper.rb
CHANGED
@@ -73,12 +73,12 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
73
73
|
elsif req.path.match /error$/
|
74
74
|
res.status = 500
|
75
75
|
end
|
76
|
-
respond_with(
|
76
|
+
respond_with("GET#{req.query_string}",req,res)
|
77
77
|
end
|
78
78
|
|
79
79
|
def do_HEAD(req,res)
|
80
80
|
res['Location'] = "/nonexistent"
|
81
|
-
respond_with(
|
81
|
+
respond_with("HEAD#{req.query_string}",req,res)
|
82
82
|
end
|
83
83
|
|
84
84
|
def do_POST(req,res)
|
@@ -103,15 +103,23 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
103
103
|
end
|
104
104
|
|
105
105
|
def do_DELETE(req,res)
|
106
|
-
respond_with(
|
106
|
+
respond_with("DELETE#{req.query_string}",req,res)
|
107
107
|
end
|
108
108
|
|
109
109
|
def do_PURGE(req,res)
|
110
|
-
respond_with(
|
110
|
+
respond_with("PURGE#{req.query_string}",req,res)
|
111
111
|
end
|
112
112
|
|
113
113
|
def do_COPY(req,res)
|
114
|
-
respond_with(
|
114
|
+
respond_with("COPY#{req.query_string}",req,res)
|
115
|
+
end
|
116
|
+
|
117
|
+
def do_PATCH(req,res)
|
118
|
+
respond_with("PATCH\n#{req.body}",req,res)
|
119
|
+
end
|
120
|
+
|
121
|
+
def do_OPTIONS(req,res)
|
122
|
+
respond_with("OPTIONS#{req.query_string}",req,res)
|
115
123
|
end
|
116
124
|
|
117
125
|
end
|
data/tests/tc_curl.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
+
|
3
|
+
class TestCurl < Test::Unit::TestCase
|
4
|
+
def test_get
|
5
|
+
curl = Curl.get(TestServlet.url, {:foo => "bar"})
|
6
|
+
assert_equal "GETfoo=bar", curl.body_str
|
7
|
+
|
8
|
+
curl = Curl.options(TestServlet.url, {:foo => "bar"}) do|http|
|
9
|
+
http.headers['Cookie'] = 'foo=1;bar=2'
|
10
|
+
end
|
11
|
+
assert_equal "OPTIONSfoo=bar", curl.body_str
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_post
|
15
|
+
curl = Curl.post(TestServlet.url, {:foo => "bar"})
|
16
|
+
assert_equal "POST\nfoo=bar", curl.body_str
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_put
|
20
|
+
curl = Curl.put(TestServlet.url, {:foo => "bar"})
|
21
|
+
assert_equal "PUT\nfoo=bar", curl.body_str
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_patch
|
25
|
+
curl = Curl.patch(TestServlet.url, {:foo => "bar"})
|
26
|
+
assert_equal "PATCH\nfoo=bar", curl.body_str
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_options
|
30
|
+
curl = Curl.options(TestServlet.url, {:foo => "bar"})
|
31
|
+
assert_equal "OPTIONSfoo=bar", curl.body_str
|
32
|
+
end
|
33
|
+
|
34
|
+
include TestServerMethods
|
35
|
+
|
36
|
+
def setup
|
37
|
+
server_setup
|
38
|
+
end
|
39
|
+
end
|
data/tests/tc_curl_easy.rb
CHANGED
@@ -988,6 +988,20 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
988
988
|
assert true, "raise in on debug has no effect"
|
989
989
|
end
|
990
990
|
|
991
|
+
def test_status_codes
|
992
|
+
curl = Curl::Easy.new(TestServlet.url)
|
993
|
+
curl.perform
|
994
|
+
assert_equal '200 OK', curl.status
|
995
|
+
end
|
996
|
+
|
997
|
+
def test_close_in_on_callbacks
|
998
|
+
curl = Curl::Easy.new(TestServlet.url)
|
999
|
+
curl.on_body {|d| curl.close; d.size }
|
1000
|
+
assert_raises RuntimeError do
|
1001
|
+
curl.perform
|
1002
|
+
end
|
1003
|
+
end
|
1004
|
+
|
991
1005
|
include TestServerMethods
|
992
1006
|
|
993
1007
|
def setup
|
data/tests/tc_curl_multi.rb
CHANGED
@@ -385,7 +385,26 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
385
385
|
end
|
386
386
|
end
|
387
387
|
|
388
|
-
def
|
388
|
+
def test_multi_easy_http_with_max_connects
|
389
|
+
urls = [
|
390
|
+
{ :url => TestServlet.url + '?q=1', :method => :get },
|
391
|
+
{ :url => TestServlet.url + '?q=2', :method => :get },
|
392
|
+
{ :url => TestServlet.url + '?q=3', :method => :get }
|
393
|
+
]
|
394
|
+
Curl::Multi.http(urls, {:pipeline => true, :max_connects => 1}) do|easy, code, method|
|
395
|
+
assert_equal nil, code
|
396
|
+
case method
|
397
|
+
when :post
|
398
|
+
assert_match /POST/, easy.body_str
|
399
|
+
when :get
|
400
|
+
assert_match /GET/, easy.body_str
|
401
|
+
when :put
|
402
|
+
assert_match /PUT/, easy.body_str
|
403
|
+
end
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def test_multi_recieves_500
|
389
408
|
m = Curl::Multi.new
|
390
409
|
e = Curl::Easy.new("http://127.0.0.1:9129/methods")
|
391
410
|
failure = false
|
metadata
CHANGED
@@ -1,28 +1,34 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: curb
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 61
|
5
5
|
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 8
|
9
|
+
- 1
|
10
|
+
version: 0.8.1
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Ross Bamford
|
9
14
|
- Todd A. Fisher
|
10
15
|
autorequire:
|
11
16
|
bindir: bin
|
12
17
|
cert_chain: []
|
13
|
-
|
18
|
+
|
19
|
+
date: 2012-06-29 00:00:00 Z
|
14
20
|
dependencies: []
|
15
|
-
|
16
|
-
|
17
|
-
libcurl live at http://curl.haxx.se/
|
21
|
+
|
22
|
+
description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings for the libcurl(3), a fully-featured client-side URL transfer library. cURL and libcurl live at http://curl.haxx.se/
|
18
23
|
email: todd.fisher@gmail.com
|
19
24
|
executables: []
|
20
|
-
|
25
|
+
|
26
|
+
extensions:
|
21
27
|
- ext/extconf.rb
|
22
|
-
extra_rdoc_files:
|
28
|
+
extra_rdoc_files:
|
23
29
|
- LICENSE
|
24
30
|
- README
|
25
|
-
files:
|
31
|
+
files:
|
26
32
|
- LICENSE
|
27
33
|
- README
|
28
34
|
- Rakefile
|
@@ -51,14 +57,17 @@ files:
|
|
51
57
|
- tests/bug_curb_easy_blocks_ruby_threads.rb
|
52
58
|
- tests/bug_curb_easy_post_with_string_no_content_length_header.rb
|
53
59
|
- tests/bug_instance_post_differs_from_class_post.rb
|
60
|
+
- tests/bug_issue102.rb
|
54
61
|
- tests/bug_multi_segfault.rb
|
55
62
|
- tests/bug_postfields_crash.rb
|
56
63
|
- tests/bug_postfields_crash2.rb
|
57
64
|
- tests/bug_require_last_or_segfault.rb
|
58
65
|
- tests/bugtests.rb
|
66
|
+
- tests/foo.rb
|
59
67
|
- tests/helper.rb
|
60
68
|
- tests/mem_check.rb
|
61
69
|
- tests/require_last_or_segfault_script.rb
|
70
|
+
- tests/tc_curl.rb
|
62
71
|
- tests/tc_curl_download.rb
|
63
72
|
- tests/tc_curl_easy.rb
|
64
73
|
- tests/tc_curl_easy_setopt.rb
|
@@ -69,46 +78,57 @@ files:
|
|
69
78
|
- tests/unittests.rb
|
70
79
|
homepage: http://curb.rubyforge.org/
|
71
80
|
licenses: []
|
81
|
+
|
72
82
|
post_install_message:
|
73
|
-
rdoc_options:
|
83
|
+
rdoc_options:
|
74
84
|
- --main
|
75
85
|
- README
|
76
|
-
require_paths:
|
86
|
+
require_paths:
|
77
87
|
- lib
|
78
88
|
- ext
|
79
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
90
|
none: false
|
81
|
-
requirements:
|
82
|
-
- -
|
83
|
-
- !ruby/object:Gem::Version
|
84
|
-
|
85
|
-
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
hash: 3
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
version: "0"
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
99
|
none: false
|
87
|
-
requirements:
|
88
|
-
- -
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
hash: 3
|
104
|
+
segments:
|
105
|
+
- 0
|
106
|
+
version: "0"
|
91
107
|
requirements: []
|
108
|
+
|
92
109
|
rubyforge_project: curb
|
93
|
-
rubygems_version: 1.8.
|
110
|
+
rubygems_version: 1.8.23
|
94
111
|
signing_key:
|
95
112
|
specification_version: 3
|
96
113
|
summary: Ruby libcurl bindings
|
97
|
-
test_files:
|
114
|
+
test_files:
|
98
115
|
- tests/alltests.rb
|
99
116
|
- tests/bug_crash_on_debug.rb
|
100
117
|
- tests/bug_crash_on_progress.rb
|
101
118
|
- tests/bug_curb_easy_blocks_ruby_threads.rb
|
102
119
|
- tests/bug_curb_easy_post_with_string_no_content_length_header.rb
|
103
120
|
- tests/bug_instance_post_differs_from_class_post.rb
|
121
|
+
- tests/bug_issue102.rb
|
104
122
|
- tests/bug_multi_segfault.rb
|
105
123
|
- tests/bug_postfields_crash.rb
|
106
124
|
- tests/bug_postfields_crash2.rb
|
107
125
|
- tests/bug_require_last_or_segfault.rb
|
108
126
|
- tests/bugtests.rb
|
127
|
+
- tests/foo.rb
|
109
128
|
- tests/helper.rb
|
110
129
|
- tests/mem_check.rb
|
111
130
|
- tests/require_last_or_segfault_script.rb
|
131
|
+
- tests/tc_curl.rb
|
112
132
|
- tests/tc_curl_download.rb
|
113
133
|
- tests/tc_curl_easy.rb
|
114
134
|
- tests/tc_curl_easy_setopt.rb
|