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 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.0"
24
- #define CURB_VER_NUM 800
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 0
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
- // XXX: no way to indicate to libcurl that we should break out given an exception in the on_debug handler... this means exceptions will be swallowed
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( ruby_curl_easy *rbce ) {
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)&proc_data_handler);
1938
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, rb_easy_get("body_proc"));//rbce->body_proc);
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)&proc_data_handler);
1949
- curl_easy_setopt(curl, CURLOPT_HEADERDATA, rb_easy_get("header_proc"));
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 CURLOPT_HEADER:
3074
- case CURLOPT_NOPROGRESS:
3075
- case CURLOPT_NOSIGNAL:
3076
- curl_easy_setopt(rbce->curl, CURLOPT_NOSIGNAL, val == Qtrue ? 1 : 0);
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
@@ -71,6 +71,8 @@ typedef struct {
71
71
  char multipart_form_post;
72
72
  char enable_cookies;
73
73
  char ignore_content_length;
74
+ char callback_active;
75
+
74
76
  struct curl_slist *curl_headers;
75
77
  struct curl_slist *curl_ftp_commands;
76
78
 
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
@@ -1,3 +1,4 @@
1
1
  require 'curb_core'
2
+ require 'curl'
2
3
  require 'curl/easy'
3
4
  require 'curl/multi'
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
- until urls_with_config.empty?
161
- m.perform do
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
- consume_free_handles.call
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(:GET,req,res)
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(:HEAD, req, res)
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(:DELETE,req,res)
106
+ respond_with("DELETE#{req.query_string}",req,res)
107
107
  end
108
108
 
109
109
  def do_PURGE(req,res)
110
- respond_with(:PURGE,req,res)
110
+ respond_with("PURGE#{req.query_string}",req,res)
111
111
  end
112
112
 
113
113
  def do_COPY(req,res)
114
- respond_with(:COPY,req,res)
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
@@ -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
@@ -385,7 +385,26 @@ class TestCurbCurlMulti < Test::Unit::TestCase
385
385
  end
386
386
  end
387
387
 
388
- def test_mutli_recieves_500
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
- version: 0.8.0
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
- date: 2012-01-19 00:00:00.000000000 Z
18
+
19
+ date: 2012-06-29 00:00:00 Z
14
20
  dependencies: []
15
- description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings
16
- for the libcurl(3), a fully-featured client-side URL transfer library. cURL and
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
- extensions:
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
- version: '0'
85
- required_rubygems_version: !ruby/object:Gem::Requirement
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
- version: '0'
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.10
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