curb 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25a6615cec70148cb19373a5ad0326a93b2e1b4424bd2d02734038857e261659
4
- data.tar.gz: 85f2b05e3fd7e8b400d8cd86d65aa2778e4c60e55337442e34d6cda673278c55
3
+ metadata.gz: 832660904f4d95f97b0795a4e39850f2fca2c70e521a0bb795a9c551f6fdf9f3
4
+ data.tar.gz: 903cb16a9a77396e90ea9ab2f33fb94a84d6a811525d23506af43195ab49fec2
5
5
  SHA512:
6
- metadata.gz: de609adca7bcd45c867a8fa91a20caa429e0064c68587d498bf25f455a1d4c49c6d00ec851af7c80aa1cc2694b4d0dd19291ebfb9b3010793dd8fa8c28e22d4c
7
- data.tar.gz: af3d577715760e6b6ca977c5a6295d0af5d8b60858d673675d778deff7b06120876b72975ea35062c5299ac45fbab2d45a70b375cf94d07b410eb8c649a443d1
6
+ metadata.gz: bf99199469304444421b00adbaa2b64707c7eddcdaff9a3c662531ebf5f2220a1b6555145fa516422921ac0980c851e7ce234ff88391d608ca6783211f364ddf
7
+ data.tar.gz: 41aec998852a8458ed9f5508f37374ac72fb170c4235a7279e4f9864d2af143281cd81e1dec6099c80765d97b2263d1ee34bebd2b193701b9a4175a024ca5991
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Curb - Libcurl bindings for Ruby
2
2
 
3
- * [CI Build Status](https://github.com/taf2/curb/actions/workflows/CI.yml)
3
+ [![CI](https://github.com/taf2/curb/actions/workflows/ci.yml/badge.svg)](https://github.com/taf2/curb/actions/workflows/ci.yml)
4
+ [![codecov](https://codecov.io/gh/taf2/curb/branch/master/graph/badge.svg)](https://codecov.io/gh/taf2/curb)
5
+ [![Gem Version](https://badge.fury.io/rb/curb.svg)](https://badge.fury.io/rb/curb)
6
+
7
+ * [CI Build Status](https://github.com/taf2/curb/actions/workflows/ci.yml)
4
8
  * [rubydoc rdoc](http://www.rubydoc.info/github/taf2/curb/)
5
9
  * [github project](http://github.com/taf2/curb/tree/master)
6
10
 
data/ext/curb.c CHANGED
@@ -143,12 +143,14 @@ static VALUE ruby_curl_asyncdns_q(VALUE mod) {
143
143
  * in RFC 2478). For libcurl versions < 7.10.8, always returns false.
144
144
  */
145
145
  static VALUE ruby_curl_spnego_q(VALUE mod) {
146
- #ifdef HAVE_CURL_VERSION_SPNEGO
147
146
  curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW);
148
- return((ver->features & CURL_VERSION_SPNEGO) ? Qtrue : Qfalse);
149
- #else
150
- return Qfalse;
147
+ #ifdef HAVE_CURL_VERSION_SPNEGO
148
+ if (ver->features & CURL_VERSION_SPNEGO) return Qtrue;
151
149
  #endif
150
+ #ifdef HAVE_CURL_VERSION_GSSNEGOTIATE
151
+ if (ver->features & CURL_VERSION_GSSNEGOTIATE) return Qtrue;
152
+ #endif
153
+ return Qfalse;
152
154
  }
153
155
 
154
156
  /*
data/ext/curb.h CHANGED
@@ -28,10 +28,10 @@
28
28
  #include "curb_macros.h"
29
29
 
30
30
  // These should be managed from the Rake 'release' task.
31
- #define CURB_VERSION "1.1.0"
32
- #define CURB_VER_NUM 1010
31
+ #define CURB_VERSION "1.2.0"
32
+ #define CURB_VER_NUM 1020
33
33
  #define CURB_VER_MAJ 1
34
- #define CURB_VER_MIN 1
34
+ #define CURB_VER_MIN 2
35
35
  #define CURB_VER_MIC 0
36
36
  #define CURB_VER_PATCH 0
37
37
 
data/ext/curb_easy.c CHANGED
@@ -12,6 +12,9 @@
12
12
 
13
13
  #include <errno.h>
14
14
  #include <string.h>
15
+ #ifndef _WIN32
16
+ #include <strings.h>
17
+ #endif
15
18
 
16
19
  extern VALUE mCurl;
17
20
 
@@ -309,6 +312,7 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
309
312
  rbce->enable_cookies = 0;
310
313
  rbce->ignore_content_length = 0;
311
314
  rbce->callback_active = 0;
315
+ rbce->last_result = 0;
312
316
  }
313
317
 
314
318
  /*
@@ -317,6 +321,9 @@ static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
317
321
  static VALUE ruby_curl_easy_allocate(VALUE klass) {
318
322
  ruby_curl_easy *rbce;
319
323
  rbce = ALLOC(ruby_curl_easy);
324
+ if (!rbce) {
325
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for Curl::Easy");
326
+ }
320
327
  rbce->curl = NULL;
321
328
  rbce->opts = Qnil;
322
329
  rbce->multi = Qnil;
@@ -375,8 +382,14 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
375
382
  static struct curl_slist *duplicate_curl_slist(struct curl_slist *list) {
376
383
  struct curl_slist *dup = NULL;
377
384
  struct curl_slist *tmp;
385
+ struct curl_slist *new_list;
378
386
  for (tmp = list; tmp; tmp = tmp->next) {
379
- dup = curl_slist_append(dup, tmp->data);
387
+ new_list = curl_slist_append(dup, tmp->data);
388
+ if (!new_list) {
389
+ if (dup) { curl_slist_free_all(dup); }
390
+ rb_raise(rb_eNoMemError, "Failed to duplicate curl_slist");
391
+ }
392
+ dup = new_list;
380
393
  }
381
394
  return dup;
382
395
  }
@@ -395,6 +408,9 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
395
408
  Data_Get_Struct(self, ruby_curl_easy, rbce);
396
409
 
397
410
  newrbce = ALLOC(ruby_curl_easy);
411
+ if (!newrbce) {
412
+ rb_raise(rb_eNoMemError, "Failed to allocate memory for Curl::Easy clone");
413
+ }
398
414
  /* shallow copy */
399
415
  memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
400
416
 
@@ -405,6 +421,9 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
405
421
  newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
406
422
  newrbce->curl_resolve = (rbce->curl_resolve) ? duplicate_curl_slist(rbce->curl_resolve) : NULL;
407
423
 
424
+ /* A cloned easy should not retain ownership reference to the original multi. */
425
+ newrbce->multi = Qnil;
426
+
408
427
  if (rbce->opts != Qnil) {
409
428
  newrbce->opts = rb_funcall(rbce->opts, rb_intern("dup"), 0);
410
429
  }
@@ -2165,7 +2184,11 @@ static VALUE cb_each_http_header(VALUE header, VALUE wrap, int _c, const VALUE *
2165
2184
 
2166
2185
  //rb_p(header_str);
2167
2186
 
2168
- *list = curl_slist_append(*list, StringValuePtr(header_str));
2187
+ struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(header_str));
2188
+ if (!new_list) {
2189
+ rb_raise(rb_eNoMemError, "Failed to append to header list");
2190
+ }
2191
+ *list = new_list;
2169
2192
  return header_str;
2170
2193
  }
2171
2194
 
@@ -2197,7 +2220,11 @@ static VALUE cb_each_http_proxy_header(VALUE proxy_header, VALUE wrap, int _c, c
2197
2220
 
2198
2221
  //rb_p(header_str);
2199
2222
 
2200
- *list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
2223
+ struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(proxy_header_str));
2224
+ if (!new_list) {
2225
+ rb_raise(rb_eNoMemError, "Failed to append to proxy header list");
2226
+ }
2227
+ *list = new_list;
2201
2228
  return proxy_header_str;
2202
2229
  }
2203
2230
 
@@ -2210,7 +2237,11 @@ static VALUE cb_each_ftp_command(VALUE ftp_command, VALUE wrap, int _c, const VA
2210
2237
  Data_Get_Struct(wrap, struct curl_slist *, list);
2211
2238
 
2212
2239
  ftp_command_string = rb_obj_as_string(ftp_command);
2213
- *list = curl_slist_append(*list, StringValuePtr(ftp_command));
2240
+ struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(ftp_command));
2241
+ if (!new_list) {
2242
+ rb_raise(rb_eNoMemError, "Failed to append to FTP command list");
2243
+ }
2244
+ *list = new_list;
2214
2245
 
2215
2246
  return ftp_command_string;
2216
2247
  }
@@ -2224,7 +2255,11 @@ static VALUE cb_each_resolve(VALUE resolve, VALUE wrap, int _c, const VALUE *_pt
2224
2255
  Data_Get_Struct(wrap, struct curl_slist *, list);
2225
2256
 
2226
2257
  resolve_string = rb_obj_as_string(resolve);
2227
- *list = curl_slist_append(*list, StringValuePtr(resolve));
2258
+ struct curl_slist *new_list = curl_slist_append(*list, StringValuePtr(resolve));
2259
+ if (!new_list) {
2260
+ rb_raise(rb_eNoMemError, "Failed to append to resolve list");
2261
+ }
2262
+ *list = new_list;
2228
2263
 
2229
2264
  return resolve_string;
2230
2265
  }
@@ -2296,6 +2331,14 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2296
2331
  curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, rb_easy_get_str("proxypwd"));
2297
2332
  }
2298
2333
 
2334
+ #if HAVE_CURLOPT_NOPROXY
2335
+ if (rb_easy_nil("noproxy")) {
2336
+ curl_easy_setopt(curl, CURLOPT_NOPROXY, NULL);
2337
+ } else {
2338
+ curl_easy_setopt(curl, CURLOPT_NOPROXY, rb_easy_get_str("noproxy"));
2339
+ }
2340
+ #endif
2341
+
2299
2342
  // body/header procs
2300
2343
  if (!rb_easy_nil("body_proc")) {
2301
2344
  curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (curl_write_callback)&proc_data_handler_body);
@@ -2517,7 +2560,11 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2517
2560
  rb_iterate(rb_each, rb_easy_get("headers"), cb_each_http_header, wrap);
2518
2561
  } else {
2519
2562
  VALUE headers_str = rb_obj_as_string(rb_easy_get("headers"));
2520
- *hdrs = curl_slist_append(*hdrs, StringValuePtr(headers_str));
2563
+ struct curl_slist *new_list = curl_slist_append(*hdrs, StringValuePtr(headers_str));
2564
+ if (!new_list) {
2565
+ rb_raise(rb_eNoMemError, "Failed to append to headers list");
2566
+ }
2567
+ *hdrs = new_list;
2521
2568
  }
2522
2569
 
2523
2570
  if (*hdrs) {
@@ -2535,7 +2582,11 @@ VALUE ruby_curl_easy_setup(ruby_curl_easy *rbce) {
2535
2582
  rb_iterate(rb_each, rb_easy_get("proxy_headers"), cb_each_http_proxy_header, wrap);
2536
2583
  } else {
2537
2584
  VALUE proxy_headers_str = rb_obj_as_string(rb_easy_get("proxy_headers"));
2538
- *phdrs = curl_slist_append(*phdrs, StringValuePtr(proxy_headers_str));
2585
+ struct curl_slist *new_list = curl_slist_append(*phdrs, StringValuePtr(proxy_headers_str));
2586
+ if (!new_list) {
2587
+ rb_raise(rb_eNoMemError, "Failed to append to proxy headers list");
2588
+ }
2589
+ *phdrs = new_list;
2539
2590
  }
2540
2591
 
2541
2592
  if (*phdrs) {
@@ -2635,10 +2686,31 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
2635
2686
 
2636
2687
  memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
2637
2688
 
2689
+ /* Use method override and adjust related options for special verbs. */
2638
2690
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
2639
2691
 
2692
+ /* For HEAD, ensure no body is requested/downloaded, as some servers
2693
+ * include a Content-Length header which should not cause libcurl to
2694
+ * wait for a body that will never arrive. */
2695
+ int is_head = (verb && (
2696
+ #ifdef _WIN32
2697
+ _stricmp(verb, "HEAD") == 0
2698
+ #else
2699
+ strcasecmp(verb, "HEAD") == 0
2700
+ #endif
2701
+ ));
2702
+ if (is_head) {
2703
+ curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
2704
+ curl_easy_setopt(curl, CURLOPT_HTTPGET, 0L);
2705
+ curl_easy_setopt(curl, CURLOPT_POST, 0L);
2706
+ }
2707
+
2640
2708
  retval = rb_funcall(self, rb_intern("perform"), 0);
2641
2709
 
2710
+ /* Restore state after request. */
2711
+ if (is_head) {
2712
+ curl_easy_setopt(curl, CURLOPT_NOBODY, 0L);
2713
+ }
2642
2714
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
2643
2715
 
2644
2716
  return retval;
@@ -3725,6 +3797,12 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3725
3797
  VALUE proxypwd = val;
3726
3798
  CURB_OBJECT_HSETTER(ruby_curl_easy, proxypwd);
3727
3799
  } break;
3800
+ #if HAVE_CURLOPT_NOPROXY
3801
+ case CURLOPT_NOPROXY: {
3802
+ VALUE noproxy = val;
3803
+ CURB_OBJECT_HSETTER(ruby_curl_easy, noproxy);
3804
+ } break;
3805
+ #endif
3728
3806
  case CURLOPT_COOKIE: {
3729
3807
  VALUE cookies = val;
3730
3808
  CURB_OBJECT_HSETTER(ruby_curl_easy, cookies);
@@ -3802,6 +3880,9 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3802
3880
  Check_Type(val, T_FILE);
3803
3881
  GetOpenFile(val, open_f_ptr);
3804
3882
  curl_easy_setopt(rbce->curl, CURLOPT_STDERR, rb_io_stdio_file(open_f_ptr));
3883
+ /* Retain a Ruby reference to the IO to prevent GC/finalization
3884
+ * while libcurl still holds and writes to the underlying FILE*. */
3885
+ rb_easy_set("stderr_io", val);
3805
3886
  break;
3806
3887
  case CURLOPT_PROTOCOLS:
3807
3888
  case CURLOPT_REDIR_PROTOCOLS:
@@ -3832,11 +3913,19 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
3832
3913
  long i, len = RARRAY_LEN(val);
3833
3914
  for (i = 0; i < len; i++) {
3834
3915
  VALUE item = rb_ary_entry(val, i);
3835
- list = curl_slist_append(list, StringValueCStr(item));
3916
+ struct curl_slist *new_list = curl_slist_append(list, StringValueCStr(item));
3917
+ if (!new_list) {
3918
+ curl_slist_free_all(list);
3919
+ rb_raise(rb_eNoMemError, "Failed to append to resolve list");
3920
+ }
3921
+ list = new_list;
3836
3922
  }
3837
3923
  } else {
3838
3924
  /* If a single string is passed, use it directly */
3839
3925
  list = curl_slist_append(NULL, StringValueCStr(val));
3926
+ if (!list) {
3927
+ rb_raise(rb_eNoMemError, "Failed to create resolve list");
3928
+ }
3840
3929
  }
3841
3930
  /* Save the list pointer in the ruby_curl_easy structure for cleanup later */
3842
3931
  rbce->curl_resolve = list;