curb 0.8.0 → 0.8.1

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.
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