curb 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.markdown +14 -19
- data/ext/curb.h +3 -3
- data/ext/curb_easy.c +54 -21
- data/ext/curb_multi.c +44 -1
- data/ext/curb_postfield.c +92 -55
- data/ext/extconf.rb +3 -1
- data/lib/curl/multi.rb +1 -1
- data/tests/helper.rb +16 -1
- data/tests/tc_curl_easy.rb +5 -5
- data/tests/tc_curl_easy_cookielist.rb +277 -0
- data/tests/tc_curl_multi.rb +9 -9
- metadata +6 -9
- data/tests/bug_issue277.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 805549f6e3fe9190d76c507fa67bf6f6e2a6bbe65bde611cb3aeee6c78cad51f
|
4
|
+
data.tar.gz: 7f6cab9c618e4535e7ff46b48d11bb5f307158d850b95bd560432dfeb9ea3144
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98f411070f4c3ef1646de29052a2c9a37e7aa2c9009102a7f4e483d1d1188d8bbdae50647e6dd4c8c7439120619e22df5f8c90bba6e1a088e2762cc29109c63d
|
7
|
+
data.tar.gz: bb8ad84d03972d1e42ce61622060019edc4d6286bab9ab459d2fe9e8ccd3cdc04490a8ba58715fd4efa30e3babf82ac96afce3f5b80fddd1d0bd4d47b197a5f1
|
data/README.markdown
CHANGED
@@ -37,18 +37,6 @@ POST request
|
|
37
37
|
puts res.body
|
38
38
|
```
|
39
39
|
|
40
|
-
PATCH request
|
41
|
-
```
|
42
|
-
res = Curl.patch("https://your-server.com/endpoint", {post: "this"}.to_json) {|http|
|
43
|
-
http.headers["Content-Type"] = "application/json"
|
44
|
-
}
|
45
|
-
puts res.code
|
46
|
-
puts res.head
|
47
|
-
puts res.body
|
48
|
-
```
|
49
|
-
|
50
|
-
|
51
|
-
|
52
40
|
## You will need
|
53
41
|
|
54
42
|
* A working Ruby installation (`2.0.0+` will work but `2.1+` preferred) (it's possible it still works with 1.8.7 but you'd have to tell me if not...)
|
@@ -64,7 +52,12 @@ tested and reported to work across a variety of platforms / rubies)
|
|
64
52
|
|
65
53
|
| Gem Version | Release Date | libcurl versions |
|
66
54
|
| ----------- | ----------- | ---------------- |
|
67
|
-
| 1.0.
|
55
|
+
| 1.0.5 | Jan 2023 | 7.58 - 7.87 |
|
56
|
+
| 1.0.4 | Jan 2023 | 7.58 - 7.87 |
|
57
|
+
| 1.0.3* | Dec 2022 | 7.58 - 7.87 |
|
58
|
+
| 1.0.2* | Dec 2022 | 7.58 - 7.87 |
|
59
|
+
| 1.0.1 | Apr 2022 | 7.58 - 7.87 |
|
60
|
+
| 1.0.0 | Jan 2022 | 7.58 - 7.87 |
|
68
61
|
| 0.9.8 | Jan 2019 | 7.58 - 7.81 |
|
69
62
|
| 0.9.7 | Nov 2018 | 7.56 - 7.60 |
|
70
63
|
| 0.9.6 | May 2018 | 7.51 - 7.59 |
|
@@ -72,6 +65,8 @@ tested and reported to work across a variety of platforms / rubies)
|
|
72
65
|
| 0.9.4 | Aug 2017 | 7.41 - 7.58 |
|
73
66
|
| 0.9.3 | Apr 2016 | 7.26 - 7.58 |
|
74
67
|
|
68
|
+
```*avoid using these version are known to have issues with segmentation faults```
|
69
|
+
|
75
70
|
## Installation...
|
76
71
|
|
77
72
|
... will usually be as simple as:
|
@@ -137,22 +132,22 @@ require 'curb'
|
|
137
132
|
|
138
133
|
```ruby
|
139
134
|
http = Curl.get("http://www.google.com/")
|
140
|
-
puts http.
|
135
|
+
puts http.body
|
141
136
|
|
142
137
|
http = Curl.post("http://www.google.com/", {:foo => "bar"})
|
143
|
-
puts http.
|
138
|
+
puts http.body
|
144
139
|
|
145
140
|
http = Curl.get("http://www.google.com/") do |http|
|
146
141
|
http.headers['Cookie'] = 'foo=1;bar=2'
|
147
142
|
end
|
148
|
-
puts http.
|
143
|
+
puts http.body
|
149
144
|
```
|
150
145
|
|
151
146
|
### Simple fetch via HTTP:
|
152
147
|
|
153
148
|
```ruby
|
154
149
|
c = Curl::Easy.perform("http://www.google.co.uk")
|
155
|
-
puts c.
|
150
|
+
puts c.body
|
156
151
|
```
|
157
152
|
|
158
153
|
Same thing, more manual:
|
@@ -160,13 +155,13 @@ Same thing, more manual:
|
|
160
155
|
```ruby
|
161
156
|
c = Curl::Easy.new("http://www.google.co.uk")
|
162
157
|
c.perform
|
163
|
-
puts c.
|
158
|
+
puts c.body
|
164
159
|
```
|
165
160
|
|
166
161
|
### Additional config:
|
167
162
|
|
168
163
|
```ruby
|
169
|
-
Curl::Easy.perform("http://www.google.co.uk") do |curl|
|
164
|
+
http = Curl::Easy.perform("http://www.google.co.uk") do |curl|
|
170
165
|
curl.headers["User-Agent"] = "myapp-0.0"
|
171
166
|
curl.verbose = true
|
172
167
|
end
|
data/ext/curb.h
CHANGED
@@ -28,11 +28,11 @@
|
|
28
28
|
#include "curb_macros.h"
|
29
29
|
|
30
30
|
// These should be managed from the Rake 'release' task.
|
31
|
-
#define CURB_VERSION "1.0.
|
32
|
-
#define CURB_VER_NUM
|
31
|
+
#define CURB_VERSION "1.0.7"
|
32
|
+
#define CURB_VER_NUM 1007
|
33
33
|
#define CURB_VER_MAJ 1
|
34
34
|
#define CURB_VER_MIN 0
|
35
|
-
#define CURB_VER_MIC
|
35
|
+
#define CURB_VER_MIC 7
|
36
36
|
#define CURB_VER_PATCH 0
|
37
37
|
|
38
38
|
|
data/ext/curb_easy.c
CHANGED
@@ -31,6 +31,7 @@ static FILE * rb_io_stdio_file(rb_io_t *fptr) {
|
|
31
31
|
return fptr->f;
|
32
32
|
}
|
33
33
|
#endif
|
34
|
+
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list);
|
34
35
|
|
35
36
|
/* ================== CURL HANDLER FUNCS ==============*/
|
36
37
|
|
@@ -79,7 +80,7 @@ static size_t read_data_handler(void *ptr,
|
|
79
80
|
remaining = len - rbcu->offset;
|
80
81
|
str_ptr = RSTRING_PTR(str);
|
81
82
|
|
82
|
-
if( remaining
|
83
|
+
if( remaining <= read_bytes ) {
|
83
84
|
if( remaining > 0 ) {
|
84
85
|
memcpy(ptr, str_ptr+rbcu->offset, remaining);
|
85
86
|
read_bytes = remaining;
|
@@ -87,14 +88,10 @@ static size_t read_data_handler(void *ptr,
|
|
87
88
|
}
|
88
89
|
return remaining;
|
89
90
|
}
|
90
|
-
else
|
91
|
+
else { // read_bytes < remaining - send what we can fit in the buffer(ptr)
|
91
92
|
memcpy(ptr, str_ptr+rbcu->offset, read_bytes);
|
92
93
|
rbcu->offset += read_bytes;
|
93
94
|
}
|
94
|
-
else { // they're equal
|
95
|
-
memcpy(ptr, str_ptr+rbcu->offset, --read_bytes);
|
96
|
-
rbcu->offset += read_bytes;
|
97
|
-
}
|
98
95
|
return read_bytes;
|
99
96
|
}
|
100
97
|
else {
|
@@ -268,7 +265,7 @@ void curl_easy_free(ruby_curl_easy *rbce) {
|
|
268
265
|
static void ruby_curl_easy_zero(ruby_curl_easy *rbce) {
|
269
266
|
rbce->opts = rb_hash_new();
|
270
267
|
|
271
|
-
memset(rbce->err_buf, 0,
|
268
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
272
269
|
|
273
270
|
rbce->curl_headers = NULL;
|
274
271
|
rbce->curl_proxy_headers = NULL;
|
@@ -374,6 +371,16 @@ static VALUE ruby_curl_easy_initialize(int argc, VALUE *argv, VALUE self) {
|
|
374
371
|
return self;
|
375
372
|
}
|
376
373
|
|
374
|
+
/* Helper to duplicate a curl_slist */
|
375
|
+
static struct curl_slist *duplicate_curl_slist(struct curl_slist *list) {
|
376
|
+
struct curl_slist *dup = NULL;
|
377
|
+
struct curl_slist *tmp;
|
378
|
+
for (tmp = list; tmp; tmp = tmp->next) {
|
379
|
+
dup = curl_slist_append(dup, tmp->data);
|
380
|
+
}
|
381
|
+
return dup;
|
382
|
+
}
|
383
|
+
|
377
384
|
/*
|
378
385
|
* call-seq:
|
379
386
|
* easy.clone => <easy clone>
|
@@ -388,14 +395,22 @@ static VALUE ruby_curl_easy_clone(VALUE self) {
|
|
388
395
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
389
396
|
|
390
397
|
newrbce = ALLOC(ruby_curl_easy);
|
398
|
+
/* shallow copy */
|
391
399
|
memcpy(newrbce, rbce, sizeof(ruby_curl_easy));
|
400
|
+
|
401
|
+
/* now deep copy */
|
392
402
|
newrbce->curl = curl_easy_duphandle(rbce->curl);
|
393
|
-
newrbce->curl_headers = NULL;
|
394
|
-
newrbce->curl_proxy_headers = NULL;
|
395
|
-
newrbce->curl_ftp_commands = NULL;
|
396
|
-
newrbce->curl_resolve = NULL;
|
403
|
+
newrbce->curl_headers = (rbce->curl_headers) ? duplicate_curl_slist(rbce->curl_headers) : NULL;
|
404
|
+
newrbce->curl_proxy_headers = (rbce->curl_proxy_headers) ? duplicate_curl_slist(rbce->curl_proxy_headers) : NULL;
|
405
|
+
newrbce->curl_ftp_commands = (rbce->curl_ftp_commands) ? duplicate_curl_slist(rbce->curl_ftp_commands) : NULL;
|
406
|
+
newrbce->curl_resolve = (rbce->curl_resolve) ? duplicate_curl_slist(rbce->curl_resolve) : NULL;
|
397
407
|
|
398
|
-
|
408
|
+
if (rbce->opts != Qnil) {
|
409
|
+
newrbce->opts = rb_funcall(rbce->opts, rb_intern("dup"), 0);
|
410
|
+
}
|
411
|
+
|
412
|
+
/* Set the error buffer on the new curl handle using the new err_buf */
|
413
|
+
curl_easy_setopt(newrbce->curl, CURLOPT_ERRORBUFFER, newrbce->err_buf);
|
399
414
|
|
400
415
|
return Data_Wrap_Struct(cCurlEasy, curl_easy_mark, curl_easy_free, newrbce);
|
401
416
|
}
|
@@ -2618,7 +2633,7 @@ static VALUE ruby_curl_easy_perform_verb_str(VALUE self, const char *verb) {
|
|
2618
2633
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2619
2634
|
curl = rbce->curl;
|
2620
2635
|
|
2621
|
-
memset(rbce->err_buf, 0,
|
2636
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
2622
2637
|
|
2623
2638
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, verb);
|
2624
2639
|
|
@@ -2685,7 +2700,7 @@ static VALUE ruby_curl_easy_perform_post(int argc, VALUE *argv, VALUE self) {
|
|
2685
2700
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2686
2701
|
curl = rbce->curl;
|
2687
2702
|
|
2688
|
-
memset(rbce->err_buf, 0,
|
2703
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
2689
2704
|
|
2690
2705
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2691
2706
|
|
@@ -2758,7 +2773,7 @@ static VALUE ruby_curl_easy_perform_put(VALUE self, VALUE data) {
|
|
2758
2773
|
Data_Get_Struct(self, ruby_curl_easy, rbce);
|
2759
2774
|
curl = rbce->curl;
|
2760
2775
|
|
2761
|
-
memset(rbce->err_buf, 0,
|
2776
|
+
memset(rbce->err_buf, 0, CURL_ERROR_SIZE);
|
2762
2777
|
|
2763
2778
|
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, NULL);
|
2764
2779
|
ruby_curl_easy_put_data_set(self, data);
|
@@ -3368,14 +3383,16 @@ static VALUE ruby_curl_easy_num_connects_get(VALUE self) {
|
|
3368
3383
|
|
3369
3384
|
/*
|
3370
3385
|
* call-seq:
|
3371
|
-
* easy.cookielist =>
|
3386
|
+
* easy.cookielist => cookielist
|
3372
3387
|
*
|
3373
3388
|
* Retrieves the cookies curl knows in an array of strings.
|
3374
3389
|
* Returned strings are in Netscape cookiejar format or in Set-Cookie format.
|
3390
|
+
* Since 7.43.0 cookies in the Set-Cookie format without a domain name are not exported.
|
3375
3391
|
*
|
3376
|
-
*
|
3377
|
-
*
|
3378
|
-
*
|
3392
|
+
* @see https://curl.se/libcurl/c/CURLINFO_COOKIELIST.html option <code>CURLINFO_COOKIELIST</code> of
|
3393
|
+
* <code>curl_easy_getopt(3)</code> to see how libcurl behaves.
|
3394
|
+
* @note requires libcurl 7.14.1 or higher, otherwise +-1+ is always returned
|
3395
|
+
* @return [Array<String>, nil, -1] array of strings, or +nil+ if there are no cookies, or +-1+ if the libcurl version is too old
|
3379
3396
|
*/
|
3380
3397
|
static VALUE ruby_curl_easy_cookielist_get(VALUE self) {
|
3381
3398
|
#ifdef HAVE_CURLINFO_COOKIELIST
|
@@ -3486,9 +3503,16 @@ static VALUE ruby_curl_easy_last_error(VALUE self) {
|
|
3486
3503
|
|
3487
3504
|
/*
|
3488
3505
|
* call-seq:
|
3489
|
-
* easy.setopt
|
3506
|
+
* easy.setopt(opt, val) => val
|
3490
3507
|
*
|
3491
3508
|
* Initial access to libcurl curl_easy_setopt
|
3509
|
+
*
|
3510
|
+
* @param [Fixnum] opt The option to set, see +Curl::CURLOPT_*+ constants
|
3511
|
+
* @param [Object] val
|
3512
|
+
* @return [Object] val
|
3513
|
+
* @raise [TypeError] if the option is not supported
|
3514
|
+
* @note Some options - like url or cookie - aren't set directly throught +curl_easy_setopt+, but stored in the Ruby object state.
|
3515
|
+
* @note When +curl_easy_setopt+ is called, return value is not checked here.
|
3492
3516
|
*/
|
3493
3517
|
static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
3494
3518
|
ruby_curl_easy *rbce;
|
@@ -3654,6 +3678,11 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3654
3678
|
curl_easy_setopt(rbce->curl, CURLOPT_SSL_SESSIONID_CACHE, NUM2LONG(val));
|
3655
3679
|
break;
|
3656
3680
|
#endif
|
3681
|
+
#if HAVE_CURLOPT_COOKIELIST
|
3682
|
+
case CURLOPT_COOKIELIST: {
|
3683
|
+
curl_easy_setopt(rbce->curl, CURLOPT_COOKIELIST, StringValueCStr(val));
|
3684
|
+
} break;
|
3685
|
+
#endif
|
3657
3686
|
#if HAVE_CURLOPT_PROXY_SSL_VERIFYHOST
|
3658
3687
|
case CURLOPT_PROXY_SSL_VERIFYHOST:
|
3659
3688
|
curl_easy_setopt(rbce->curl, CURLOPT_PROXY_SSL_VERIFYHOST, NUM2LONG(val));
|
@@ -3668,9 +3697,13 @@ static VALUE ruby_curl_easy_set_opt(VALUE self, VALUE opt, VALUE val) {
|
|
3668
3697
|
|
3669
3698
|
/*
|
3670
3699
|
* call-seq:
|
3671
|
-
* easy.getinfo
|
3700
|
+
* easy.getinfo(opt) => nil
|
3672
3701
|
*
|
3673
3702
|
* Iniital access to libcurl curl_easy_getinfo, remember getinfo doesn't return the same values as setopt
|
3703
|
+
*
|
3704
|
+
* @note This method is not implemented yet.
|
3705
|
+
* @param [Fixnum] code Constant +CURLINFO_*+ from libcurl
|
3706
|
+
* @return [nil]
|
3674
3707
|
*/
|
3675
3708
|
static VALUE ruby_curl_easy_get_opt(VALUE self, VALUE opt) {
|
3676
3709
|
return Qnil;
|
data/ext/curb_multi.c
CHANGED
@@ -27,6 +27,21 @@
|
|
27
27
|
#include <fcntl.h>
|
28
28
|
#endif
|
29
29
|
|
30
|
+
#ifdef HAVE_CURL_MULTI_WAIT
|
31
|
+
#include <stdint.h> /* for intptr_t */
|
32
|
+
|
33
|
+
struct wait_args {
|
34
|
+
CURLM *handle;
|
35
|
+
long timeout_ms;
|
36
|
+
int numfds;
|
37
|
+
};
|
38
|
+
static void *curl_multi_wait_wrapper(void *p) {
|
39
|
+
struct wait_args *args = p;
|
40
|
+
CURLMcode code = curl_multi_wait(args->handle, NULL, 0, args->timeout_ms, &args->numfds);
|
41
|
+
return (void *)(intptr_t)code;
|
42
|
+
}
|
43
|
+
#endif
|
44
|
+
|
30
45
|
extern VALUE mCurl;
|
31
46
|
static VALUE idCall;
|
32
47
|
|
@@ -226,6 +241,8 @@ VALUE ruby_curl_multi_add(VALUE self, VALUE easy) {
|
|
226
241
|
|
227
242
|
mcode = curl_multi_add_handle(rbcm->handle, rbce->curl);
|
228
243
|
if (mcode != CURLM_CALL_MULTI_PERFORM && mcode != CURLM_OK) {
|
244
|
+
ruby_curl_easy_cleanup(easy, rbce);
|
245
|
+
|
229
246
|
raise_curl_multi_error_exception(mcode);
|
230
247
|
}
|
231
248
|
|
@@ -264,6 +281,7 @@ VALUE ruby_curl_multi_remove(VALUE self, VALUE rb_easy_handle) {
|
|
264
281
|
|
265
282
|
return self;
|
266
283
|
}
|
284
|
+
|
267
285
|
static void rb_curl_multi_remove(ruby_curl_multi *rbcm, VALUE easy) {
|
268
286
|
CURLMcode result;
|
269
287
|
ruby_curl_easy *rbce;
|
@@ -528,7 +546,6 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
528
546
|
|
529
547
|
do {
|
530
548
|
while (rbcm->running) {
|
531
|
-
|
532
549
|
#ifdef HAVE_CURL_MULTI_TIMEOUT
|
533
550
|
/* get the curl suggested time out */
|
534
551
|
mcode = curl_multi_timeout(rbcm->handle, &timeout_milliseconds);
|
@@ -552,6 +569,31 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
552
569
|
/* or buggy versions libcurl sometimes reports huge timeouts... let's cap it */
|
553
570
|
}
|
554
571
|
|
572
|
+
#ifdef HAVE_CURL_MULTI_WAIT
|
573
|
+
{
|
574
|
+
struct wait_args wait_args;
|
575
|
+
wait_args.handle = rbcm->handle;
|
576
|
+
wait_args.timeout_ms = timeout_milliseconds;
|
577
|
+
wait_args.numfds = 0;
|
578
|
+
#if defined(HAVE_RB_THREAD_CALL_WITHOUT_GVL)
|
579
|
+
CURLMcode wait_rc = (CURLMcode)(intptr_t)
|
580
|
+
rb_thread_call_without_gvl(curl_multi_wait_wrapper, &wait_args, RUBY_UBF_IO, NULL);
|
581
|
+
#else
|
582
|
+
CURLMcode wait_rc = curl_multi_wait(rbcm->handle, NULL, 0, timeout_milliseconds, &wait_args.numfds);
|
583
|
+
#endif
|
584
|
+
if (wait_rc != CURLM_OK) {
|
585
|
+
raise_curl_multi_error_exception(wait_rc);
|
586
|
+
}
|
587
|
+
if (wait_args.numfds == 0) {
|
588
|
+
rb_thread_wait_for(tv_100ms);
|
589
|
+
}
|
590
|
+
/* Process pending transfers after waiting */
|
591
|
+
rb_curl_multi_run(self, rbcm->handle, &(rbcm->running));
|
592
|
+
rb_curl_multi_read_info(self, rbcm->handle);
|
593
|
+
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
594
|
+
}
|
595
|
+
#else
|
596
|
+
|
555
597
|
tv.tv_sec = 0; /* never wait longer than 1 second */
|
556
598
|
tv.tv_usec = (int)(timeout_milliseconds * 1000); /* XXX: int is the right type for OSX, what about linux? */
|
557
599
|
|
@@ -618,6 +660,7 @@ VALUE ruby_curl_multi_perform(int argc, VALUE *argv, VALUE self) {
|
|
618
660
|
if (block != Qnil) { rb_funcall(block, rb_intern("call"), 1, self); }
|
619
661
|
break;
|
620
662
|
}
|
663
|
+
#endif /* HAVE_CURL_MULTI_WAIT */
|
621
664
|
}
|
622
665
|
|
623
666
|
} while( rbcm->running );
|
data/ext/curb_postfield.c
CHANGED
@@ -421,71 +421,108 @@ static VALUE ruby_curl_postfield_content_proc_set(int argc, VALUE *argv, VALUE s
|
|
421
421
|
* Only content fields may be converted to strings.
|
422
422
|
*/
|
423
423
|
static VALUE ruby_curl_postfield_to_str(VALUE self) {
|
424
|
-
// FIXME This is using the deprecated curl_escape func
|
425
424
|
ruby_curl_postfield *rbcpf;
|
426
425
|
VALUE result = Qnil;
|
427
426
|
VALUE name = Qnil;
|
428
427
|
char *tmpchrs;
|
429
|
-
|
428
|
+
#ifdef HAVE_CURL_EASY_ESCAPE
|
429
|
+
CURL *curl_handle = NULL;
|
430
|
+
#endif
|
431
|
+
|
430
432
|
Data_Get_Struct(self, ruby_curl_postfield, rbcpf);
|
431
433
|
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
} else if (rb_respond_to(name,rb_intern("to_s"))) {
|
434
|
+
if (rbcpf->name != Qnil) {
|
435
|
+
name = rbcpf->name;
|
436
|
+
if (TYPE(name) != T_STRING) {
|
437
|
+
if (rb_respond_to(name, rb_intern("to_s")))
|
437
438
|
name = rb_funcall(name, rb_intern("to_s"), 0);
|
438
|
-
|
439
|
-
|
440
|
-
name = Qnil; // we can't handle this object
|
441
|
-
}
|
442
|
-
}
|
443
|
-
if (name == Qnil) {
|
444
|
-
rb_raise(eCurlErrInvalidPostField, "Cannot convert unnamed field to string %s:%d, make sure your field name responds_to :to_s", __FILE__, __LINE__);
|
439
|
+
else
|
440
|
+
name = Qnil;
|
445
441
|
}
|
442
|
+
}
|
443
|
+
if (name == Qnil) {
|
444
|
+
rb_raise(eCurlErrInvalidPostField,
|
445
|
+
"Cannot convert unnamed field to string %s:%d, make sure your field name responds_to :to_s",
|
446
|
+
__FILE__, __LINE__);
|
447
|
+
}
|
448
|
+
/* Force field name to UTF-8 before escaping */
|
449
|
+
VALUE name_utf8 = rb_str_export_to_enc(name, rb_utf8_encoding());
|
446
450
|
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
451
|
+
#ifdef HAVE_CURL_EASY_ESCAPE
|
452
|
+
curl_handle = curl_easy_init();
|
453
|
+
if (!curl_handle) {
|
454
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to initialize curl handle for escaping");
|
455
|
+
}
|
456
|
+
tmpchrs = curl_easy_escape(curl_handle, StringValuePtr(name_utf8), (int)RSTRING_LEN(name_utf8));
|
457
|
+
if (!tmpchrs) {
|
458
|
+
curl_easy_cleanup(curl_handle);
|
459
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name");
|
460
|
+
}
|
461
|
+
#else
|
462
|
+
tmpchrs = curl_escape(StringValuePtr(name_utf8), (int)RSTRING_LEN(name_utf8));
|
463
|
+
if (!tmpchrs) {
|
464
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode name");
|
465
|
+
}
|
466
|
+
#endif
|
467
|
+
|
468
|
+
VALUE escd_name = rb_str_new2(tmpchrs);
|
469
|
+
#ifdef HAVE_CURL_EASY_ESCAPE
|
470
|
+
curl_free(tmpchrs);
|
471
|
+
#else
|
472
|
+
curl_free(tmpchrs);
|
473
|
+
#endif
|
474
|
+
|
475
|
+
VALUE tmpcontent = Qnil;
|
476
|
+
if (rbcpf->content_proc != Qnil) {
|
477
|
+
tmpcontent = rb_funcall(rbcpf->content_proc, idCall, 1, self);
|
478
|
+
} else if (rbcpf->content != Qnil) {
|
479
|
+
tmpcontent = rbcpf->content;
|
480
|
+
} else if (rbcpf->local_file != Qnil) {
|
481
|
+
tmpcontent = rbcpf->local_file;
|
482
|
+
} else if (rbcpf->remote_file != Qnil) {
|
483
|
+
tmpcontent = rbcpf->remote_file;
|
484
|
+
} else {
|
485
|
+
tmpcontent = rb_str_new2("");
|
486
|
+
}
|
487
|
+
if (TYPE(tmpcontent) != T_STRING) {
|
488
|
+
if (rb_respond_to(tmpcontent, rb_intern("to_s")))
|
489
|
+
tmpcontent = rb_funcall(tmpcontent, rb_intern("to_s"), 0);
|
490
|
+
else {
|
491
|
+
#ifdef HAVE_CURL_EASY_ESCAPE
|
492
|
+
curl_easy_cleanup(curl_handle);
|
493
|
+
#endif
|
494
|
+
rb_raise(rb_eRuntimeError,
|
495
|
+
"postfield(%s) is not a string and does not respond_to to_s",
|
496
|
+
RSTRING_PTR(escd_name));
|
487
497
|
}
|
488
|
-
|
498
|
+
}
|
499
|
+
/* Force content to UTF-8 before escaping */
|
500
|
+
VALUE content_utf8 = rb_str_export_to_enc(tmpcontent, rb_utf8_encoding());
|
501
|
+
#ifdef HAVE_CURL_EASY_ESCAPE
|
502
|
+
tmpchrs = curl_easy_escape(curl_handle, StringValuePtr(content_utf8), (int)RSTRING_LEN(content_utf8));
|
503
|
+
if (!tmpchrs) {
|
504
|
+
curl_easy_cleanup(curl_handle);
|
505
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content");
|
506
|
+
}
|
507
|
+
#else
|
508
|
+
tmpchrs = curl_escape(StringValuePtr(content_utf8), (int)RSTRING_LEN(content_utf8));
|
509
|
+
if (!tmpchrs) {
|
510
|
+
rb_raise(eCurlErrInvalidPostField, "Failed to url-encode content");
|
511
|
+
}
|
512
|
+
#endif
|
513
|
+
|
514
|
+
VALUE escd_content = rb_str_new2(tmpchrs);
|
515
|
+
#ifdef HAVE_CURL_EASY_ESCAPE
|
516
|
+
curl_free(tmpchrs);
|
517
|
+
curl_easy_cleanup(curl_handle);
|
518
|
+
#else
|
519
|
+
curl_free(tmpchrs);
|
520
|
+
#endif
|
521
|
+
|
522
|
+
result = escd_name;
|
523
|
+
rb_str_cat(result, "=", 1);
|
524
|
+
rb_str_concat(result, escd_content);
|
525
|
+
|
489
526
|
return result;
|
490
527
|
}
|
491
528
|
|
data/ext/extconf.rb
CHANGED
@@ -9,7 +9,7 @@ if find_executable('curl-config')
|
|
9
9
|
else
|
10
10
|
$LIBS << " #{`curl-config --libs`.strip}"
|
11
11
|
end
|
12
|
-
ca_bundle_path=`curl-config --ca`.strip
|
12
|
+
ca_bundle_path=`curl-config --ca`.strip.gsub(/^"([^"]+)"$/,'\1')
|
13
13
|
if !ca_bundle_path.nil? and ca_bundle_path != ''
|
14
14
|
$defs.push( %{-D HAVE_CURL_CONFIG_CA} )
|
15
15
|
$defs.push( %{-D CURL_CONFIG_CA='#{ca_bundle_path.inspect}'} )
|
@@ -467,6 +467,8 @@ have_func('rb_thread_blocking_region')
|
|
467
467
|
have_header('ruby/thread.h') && have_func('rb_thread_call_without_gvl', 'ruby/thread.h')
|
468
468
|
have_header('ruby/io.h')
|
469
469
|
have_func('rb_io_stdio_file')
|
470
|
+
have_func('curl_multi_wait')
|
471
|
+
have_func('curl_easy_duphandle')
|
470
472
|
|
471
473
|
create_header('curb_config.h')
|
472
474
|
create_makefile('curb_core')
|
data/lib/curl/multi.rb
CHANGED
@@ -95,7 +95,7 @@ module Curl
|
|
95
95
|
|
96
96
|
# configure the multi handle
|
97
97
|
multi_options.each { |k,v| m.send("#{k}=", v) }
|
98
|
-
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_redirect,:on_body,:on_header]
|
98
|
+
callbacks = [:on_progress,:on_debug,:on_failure,:on_success,:on_redirect,:on_missing,:on_body,:on_header]
|
99
99
|
|
100
100
|
add_free_handle = proc do|conf, easy|
|
101
101
|
c = conf.dup # avoid being destructive to input
|
data/tests/helper.rb
CHANGED
@@ -80,6 +80,10 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
80
80
|
res.status = 404
|
81
81
|
elsif req.path.match(/error$/)
|
82
82
|
res.status = 500
|
83
|
+
elsif req.path.match(/get_cookies$/)
|
84
|
+
res['Content-Type'] = "text/plain"
|
85
|
+
res.body = req['Cookie']
|
86
|
+
return
|
83
87
|
end
|
84
88
|
respond_with("GET#{req.query_string}",req,res)
|
85
89
|
end
|
@@ -90,7 +94,18 @@ class TestServlet < WEBrick::HTTPServlet::AbstractServlet
|
|
90
94
|
end
|
91
95
|
|
92
96
|
def do_POST(req,res)
|
93
|
-
if req.
|
97
|
+
if req.path.match(/set_cookies$/)
|
98
|
+
JSON.parse(req.body || '[]', symbolize_names: true).each do |hash|
|
99
|
+
cookie = WEBrick::Cookie.new(hash.fetch(:name), hash.fetch(:value))
|
100
|
+
cookie.domain = hash[:domain] if hash.key?(:domain)
|
101
|
+
cookie.expires = hash[:expires] if hash.key?(:expires)
|
102
|
+
cookie.path = hash[:path] if hash.key?(:path)
|
103
|
+
cookie.secure = hash[:secure] if hash.key?(:secure)
|
104
|
+
cookie.max_age = hash[:max_age] if hash.key?(:max_age)
|
105
|
+
res.cookies.push(cookie)
|
106
|
+
end
|
107
|
+
respond_with('OK', req, res)
|
108
|
+
elsif req.query['filename'].nil?
|
94
109
|
if req.body
|
95
110
|
params = {}
|
96
111
|
req.body.split('&').map{|s| k,v=s.split('='); params[k] = v }
|
data/tests/tc_curl_easy.rb
CHANGED
@@ -110,7 +110,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
110
110
|
end
|
111
111
|
|
112
112
|
def test_class_perform_02
|
113
|
-
data =
|
113
|
+
data = String.new
|
114
114
|
assert_instance_of Curl::Easy, c = Curl::Easy.perform($TEST_URL) { |curl| curl.on_body { |d| data << d; d.length } }
|
115
115
|
|
116
116
|
assert_nil c.body_str
|
@@ -211,7 +211,7 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
211
211
|
end
|
212
212
|
|
213
213
|
def test_get_02
|
214
|
-
data =
|
214
|
+
data = String.new
|
215
215
|
c = Curl::Easy.new($TEST_URL) do |curl|
|
216
216
|
curl.on_body { |d| data << d; d.length }
|
217
217
|
end
|
@@ -1068,13 +1068,13 @@ class TestCurbCurlEasy < Test::Unit::TestCase
|
|
1068
1068
|
end
|
1069
1069
|
|
1070
1070
|
def test_easy_http_verbs_must_respond_to_str
|
1071
|
-
# issue http://github.com/taf2/curb/issues
|
1071
|
+
# issue http://github.com/taf2/curb/issues/45
|
1072
1072
|
assert_nothing_raised do
|
1073
|
-
c = Curl::Easy.new ; c.url =
|
1073
|
+
c = Curl::Easy.new ; c.url = TestServlet.url ; c.http(:get)
|
1074
1074
|
end
|
1075
1075
|
|
1076
1076
|
assert_raise RuntimeError do
|
1077
|
-
c = Curl::Easy.new ; c.url =
|
1077
|
+
c = Curl::Easy.new ; c.url = TestServlet.url ; c.http(FooNoToS.new)
|
1078
1078
|
end
|
1079
1079
|
|
1080
1080
|
end
|
@@ -0,0 +1,277 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
class TestCurbCurlEasyCookielist < Test::Unit::TestCase
|
5
|
+
def test_setopt_cookielist
|
6
|
+
easy = Curl::Easy.new
|
7
|
+
# DateTime handles time zone correctly
|
8
|
+
expires = (Date.today + 2).to_datetime
|
9
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c1=v1; domain=localhost; expires=#{expires.httpdate};")
|
10
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: c2=v2; domain=localhost')
|
11
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c3=v3; expires=#{expires.httpdate};")
|
12
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: c4=v4;')
|
13
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c5=v5; domain=127.0.0.1; expires=#{expires.httpdate};")
|
14
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: c6=v6; domain=127.0.0.1;;')
|
15
|
+
|
16
|
+
# Since 7.43.0 cookies that were imported in the Set-Cookie format without a domain name are not exported by this option.
|
17
|
+
# So, before 7.43.0, c3 and c4 will be exported too; but that version is far too old for current curb version, so it's not handled here.
|
18
|
+
if Curl::CURL_VERSION.to_f > 8
|
19
|
+
expected_cookielist = [
|
20
|
+
".127.0.0.1\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc5\tv5",
|
21
|
+
".127.0.0.1\tTRUE\t/\tFALSE\t0\tc6\tv6",
|
22
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc1\tv1",
|
23
|
+
".localhost\tTRUE\t/\tFALSE\t0\tc2\tv2",
|
24
|
+
]
|
25
|
+
else
|
26
|
+
expected_cookielist = [
|
27
|
+
"127.0.0.1\tFALSE\t/\tFALSE\t#{expires.to_time.to_i}\tc5\tv5",
|
28
|
+
"127.0.0.1\tFALSE\t/\tFALSE\t0\tc6\tv6",
|
29
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc1\tv1",
|
30
|
+
".localhost\tTRUE\t/\tFALSE\t0\tc2\tv2",
|
31
|
+
]
|
32
|
+
end
|
33
|
+
assert_equal expected_cookielist, easy.cookielist
|
34
|
+
|
35
|
+
easy.url = "#{TestServlet.url}/get_cookies"
|
36
|
+
easy.perform
|
37
|
+
assert_equal 'c6=v6; c5=v5; c4=v4; c3=v3', easy.body_str
|
38
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
39
|
+
easy.perform
|
40
|
+
assert_equal 'c2=v2; c1=v1', easy.body_str
|
41
|
+
end
|
42
|
+
|
43
|
+
# libcurl documentation says: "This option also enables the cookie engine", but it's not tracked on the curb level
|
44
|
+
def test_setopt_cookielist_enables_cookie_engine
|
45
|
+
easy = Curl::Easy.new
|
46
|
+
expires = (Date.today + 2).to_datetime
|
47
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/set_cookies"
|
48
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: c1=v1; domain=localhost; expires=#{expires.httpdate};")
|
49
|
+
easy.post_body = JSON.generate([{ name: 'c2', value: 'v2', domain: 'localhost', expires: expires.httpdate, path: '/' }])
|
50
|
+
easy.perform
|
51
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
52
|
+
easy.post_body = nil
|
53
|
+
easy.perform
|
54
|
+
|
55
|
+
assert !easy.enable_cookies?
|
56
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc1\tv1", ".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc2\tv2"], easy.cookielist
|
57
|
+
assert_equal 'c2=v2; c1=v1', easy.body_str
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_setopt_cookielist_invalid_format
|
61
|
+
easy = Curl::Easy.new
|
62
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
63
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Not a cookie')
|
64
|
+
assert_nil easy.cookielist
|
65
|
+
easy.perform
|
66
|
+
assert_equal '', easy.body_str
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_setopt_cookielist_netscape_format
|
70
|
+
easy = Curl::Easy.new
|
71
|
+
expires = (Date.today + 2).to_datetime
|
72
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
73
|
+
# Note domain changes for include subdomains
|
74
|
+
[
|
75
|
+
['localhost', 'FALSE', '/', 'TRUE', 0, 'session_http_only', '42'].join("\t"),
|
76
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '43'].join("\t"),
|
77
|
+
['localhost', 'TRUE', '/', 'FALSE', expires.to_time.to_i, 'permanent', '44'].join("\t"),
|
78
|
+
['.localhost', 'FALSE', '/', 'TRUE', expires.to_time.to_i, 'permanent_http_only', '45'].join("\t"),
|
79
|
+
].each { |cookie| easy.setopt(Curl::CURLOPT_COOKIELIST, cookie) }
|
80
|
+
|
81
|
+
expected_cookielist = [
|
82
|
+
['localhost', 'FALSE', '/', 'TRUE', 0, 'session_http_only', '42'].join("\t"),
|
83
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '43'].join("\t"),
|
84
|
+
['.localhost', 'TRUE', '/', 'FALSE', expires.to_time.to_i, 'permanent', '44'].join("\t"),
|
85
|
+
['localhost', 'FALSE', '/', 'TRUE', expires.to_time.to_i, 'permanent_http_only', '45'].join("\t"),
|
86
|
+
]
|
87
|
+
assert_equal expected_cookielist, easy.cookielist
|
88
|
+
easy.perform
|
89
|
+
assert_equal 'permanent_http_only=45; session_http_only=42; permanent=44; session=43', easy.body_str
|
90
|
+
end
|
91
|
+
|
92
|
+
# Multiple cookies and comments are not supported
|
93
|
+
def test_setopt_cookielist_netscape_format_mutliline
|
94
|
+
easy = Curl::Easy.new
|
95
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
96
|
+
easy.setopt(
|
97
|
+
Curl::CURLOPT_COOKIELIST,
|
98
|
+
[
|
99
|
+
'# Netscape HTTP Cookie File',
|
100
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '42'].join("\t"),
|
101
|
+
'',
|
102
|
+
].join("\n"),
|
103
|
+
)
|
104
|
+
assert_nil easy.cookielist
|
105
|
+
easy.perform
|
106
|
+
assert_equal '', easy.body_str
|
107
|
+
|
108
|
+
easy.setopt(
|
109
|
+
Curl::CURLOPT_COOKIELIST,
|
110
|
+
[
|
111
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session', '42'].join("\t"),
|
112
|
+
['.localhost', 'TRUE', '/', 'FALSE', 0, 'session2', '84'].join("\t"),
|
113
|
+
'',
|
114
|
+
].join("\n"),
|
115
|
+
)
|
116
|
+
# Only first cookie is set
|
117
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t0\tsession\t42"], easy.cookielist
|
118
|
+
easy.perform
|
119
|
+
assert_equal 'session=42', easy.body_str
|
120
|
+
end
|
121
|
+
|
122
|
+
# ALL erases all cookies held in memory
|
123
|
+
# ALL was added in 7.14.1
|
124
|
+
def test_setopt_cookielist_command_all
|
125
|
+
expires = (Date.today + 2).to_datetime
|
126
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
127
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'ALL')
|
128
|
+
assert_nil easy.cookielist
|
129
|
+
easy.perform
|
130
|
+
assert_equal '', easy.body_str
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# SESS erases all session cookies held in memory
|
135
|
+
# SESS was added in 7.15.4
|
136
|
+
def test_setopt_cookielist_command_sess
|
137
|
+
expires = (Date.today + 2).to_datetime
|
138
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
139
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'SESS')
|
140
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tpermanent\t42"], easy.cookielist
|
141
|
+
easy.perform
|
142
|
+
assert_equal 'permanent=42', easy.body_str
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# FLUSH writes all known cookies to the file specified by CURLOPT_COOKIEJAR
|
147
|
+
# FLUSH was added in 7.17.1
|
148
|
+
def test_setopt_cookielist_command_flush
|
149
|
+
expires = (Date.today + 2).to_datetime
|
150
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
151
|
+
cookiejar = File.join(Dir.tmpdir, 'curl_test_cookiejar')
|
152
|
+
assert !File.exist?(cookiejar)
|
153
|
+
begin
|
154
|
+
easy.cookiejar = cookiejar
|
155
|
+
# trick to actually set CURLOPT_COOKIEJAR
|
156
|
+
easy.enable_cookies = true
|
157
|
+
easy.perform
|
158
|
+
assert !File.exist?(cookiejar)
|
159
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'FLUSH')
|
160
|
+
expected_cookiejar = <<~COOKIEJAR
|
161
|
+
# Netscape HTTP Cookie File
|
162
|
+
# https://curl.se/docs/http-cookies.html
|
163
|
+
# This file was generated by libcurl! Edit at your own risk.
|
164
|
+
|
165
|
+
.localhost TRUE / FALSE 0 session 420
|
166
|
+
.localhost TRUE / FALSE #{expires.to_time.to_i} permanent 42
|
167
|
+
COOKIEJAR
|
168
|
+
assert_equal expected_cookiejar, File.read(cookiejar)
|
169
|
+
ensure
|
170
|
+
# Otherwise it'll create this file again
|
171
|
+
easy.close
|
172
|
+
File.unlink(cookiejar) if File.exist?(cookiejar)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# RELOAD loads all cookies from the files specified by CURLOPT_COOKIEFILE
|
178
|
+
# RELOAD was added in 7.39.0
|
179
|
+
def test_setopt_cookielist_command_reload
|
180
|
+
expires = (Date.today + 2).to_datetime
|
181
|
+
expires_file = (Date.today + 4).to_datetime
|
182
|
+
with_permanent_and_session_cookies(expires) do |easy|
|
183
|
+
cookiefile = File.join(Dir.tmpdir, 'curl_test_cookiefile')
|
184
|
+
assert !File.exist?(cookiefile)
|
185
|
+
begin
|
186
|
+
cookielist = [
|
187
|
+
# Won't be updated, added instead
|
188
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent\t84",
|
189
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent_file\t84",
|
190
|
+
# Won't be updated, added instead
|
191
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession\t840",
|
192
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession_file\t840",
|
193
|
+
'',
|
194
|
+
]
|
195
|
+
File.write(cookiefile, cookielist.join("\n"))
|
196
|
+
easy.cookiefile = cookiefile
|
197
|
+
# trick to actually set CURLOPT_COOKIEFILE
|
198
|
+
easy.enable_cookies = true
|
199
|
+
easy.perform
|
200
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'RELOAD')
|
201
|
+
expected_cookielist = [
|
202
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tpermanent\t42",
|
203
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession\t420",
|
204
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent\t84",
|
205
|
+
".localhost\tTRUE\t/\tFALSE\t#{expires_file.to_time.to_i}\tpermanent_file\t84",
|
206
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession\t840",
|
207
|
+
".localhost\tTRUE\t/\tFALSE\t0\tsession_file\t840",
|
208
|
+
]
|
209
|
+
assert_equal expected_cookielist, easy.cookielist
|
210
|
+
easy.perform
|
211
|
+
# Be careful, duplicates are not removed
|
212
|
+
assert_equal 'permanent_file=84; session_file=840; permanent=84; session=840; permanent=42; session=420', easy.body_str
|
213
|
+
ensure
|
214
|
+
File.unlink(cookiefile) if File.exist?(cookiefile)
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_commands_do_not_enable_cookie_engine
|
220
|
+
%w[ALL SESS FLUSH RELOAD].each do |command|
|
221
|
+
easy = Curl::Easy.new
|
222
|
+
expires = (Date.today + 2).to_datetime
|
223
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/set_cookies"
|
224
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, command)
|
225
|
+
easy.post_body = JSON.generate([{ name: 'c2', value: 'v2', domain: 'localhost', expires: expires.httpdate, path: '/' }])
|
226
|
+
easy.perform
|
227
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
228
|
+
easy.post_body = nil
|
229
|
+
easy.perform
|
230
|
+
|
231
|
+
assert !easy.enable_cookies?
|
232
|
+
assert_nil easy.cookielist
|
233
|
+
assert_equal '', easy.body_str
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
|
238
|
+
def test_strings_without_cookie_enable_cookie_engine
|
239
|
+
[
|
240
|
+
'',
|
241
|
+
'# Netscape HTTP Cookie File',
|
242
|
+
'no_a_cookie',
|
243
|
+
].each do |command|
|
244
|
+
easy = Curl::Easy.new
|
245
|
+
expires = (Date.today + 2).to_datetime
|
246
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/set_cookies"
|
247
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, command)
|
248
|
+
easy.post_body = JSON.generate([{ name: 'c2', value: 'v2', domain: 'localhost', expires: expires.httpdate, path: '/' }])
|
249
|
+
easy.perform
|
250
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
251
|
+
easy.post_body = nil
|
252
|
+
easy.perform
|
253
|
+
|
254
|
+
assert !easy.enable_cookies?
|
255
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tc2\tv2"], easy.cookielist
|
256
|
+
assert_equal 'c2=v2', easy.body_str
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def with_permanent_and_session_cookies(expires)
|
261
|
+
easy = Curl::Easy.new
|
262
|
+
easy.url = "http://localhost:#{TestServlet.port}#{TestServlet.path}/get_cookies"
|
263
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, "Set-Cookie: permanent=42; domain=localhost; expires=#{expires.httpdate};")
|
264
|
+
easy.setopt(Curl::CURLOPT_COOKIELIST, 'Set-Cookie: session=420; domain=localhost;')
|
265
|
+
assert_equal [".localhost\tTRUE\t/\tFALSE\t#{expires.to_time.to_i}\tpermanent\t42", ".localhost\tTRUE\t/\tFALSE\t0\tsession\t420"], easy.cookielist
|
266
|
+
easy.perform
|
267
|
+
assert_equal 'permanent=42; session=420', easy.body_str
|
268
|
+
|
269
|
+
yield easy
|
270
|
+
end
|
271
|
+
|
272
|
+
include TestServerMethods
|
273
|
+
|
274
|
+
def setup
|
275
|
+
server_setup
|
276
|
+
end
|
277
|
+
end
|
data/tests/tc_curl_multi.rb
CHANGED
@@ -13,7 +13,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
13
13
|
# this test fails with libcurl 7.22.0. I didn't investigate, but it may be related
|
14
14
|
# to CURLOPT_MAXCONNECTS bug fixed in 7.30.0:
|
15
15
|
# https://github.com/curl/curl/commit/e87e76e2dc108efb1cae87df496416f49c55fca0
|
16
|
-
omit("Skip, libcurl too old (< 7.22.0)") if Curl::CURL_VERSION.split('.')[1].to_i <= 22
|
16
|
+
omit("Skip, libcurl too old (< 7.22.0)") if Curl::CURL_VERSION.to_f < 8 && Curl::CURL_VERSION.split('.')[1].to_i <= 22
|
17
17
|
|
18
18
|
@server.shutdown if @server
|
19
19
|
@test_thread.kill if @test_thread
|
@@ -114,13 +114,13 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def test_new_multi_01
|
117
|
-
d1 =
|
117
|
+
d1 = String.new
|
118
118
|
c1 = Curl::Easy.new($TEST_URL) do |curl|
|
119
119
|
curl.headers["User-Agent"] = "myapp-0.0"
|
120
120
|
curl.on_body {|d| d1 << d; d.length }
|
121
121
|
end
|
122
122
|
|
123
|
-
d2 =
|
123
|
+
d2 = String.new
|
124
124
|
c2 = Curl::Easy.new($TEST_URL) do |curl|
|
125
125
|
curl.headers["User-Agent"] = "myapp-0.0"
|
126
126
|
curl.on_body {|d| d2 << d; d.length }
|
@@ -186,7 +186,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
186
186
|
rescue Curl::Err::AbortedByCallbackError => e
|
187
187
|
did_raise = true
|
188
188
|
in_file = e.backtrace.detect {|err| err.match?(File.basename(__FILE__)) }
|
189
|
-
in_file_stack = e.backtrace.select {|err| err.match?(File.basename(__FILE__)) }
|
189
|
+
#in_file_stack = e.backtrace.select {|err| err.match?(File.basename(__FILE__)) }
|
190
190
|
assert_match(__FILE__, in_file)
|
191
191
|
in_file.gsub!(__FILE__)
|
192
192
|
parts = in_file.split(':')
|
@@ -206,7 +206,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
206
206
|
m = Curl::Multi.new
|
207
207
|
responses = []
|
208
208
|
n.times do|i|
|
209
|
-
responses[i] =
|
209
|
+
responses[i] = String.new
|
210
210
|
c = Curl::Easy.new($TEST_URL) do|curl|
|
211
211
|
curl.on_body{|data| responses[i] << data; data.size }
|
212
212
|
end
|
@@ -230,7 +230,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
230
230
|
5.times do|it|
|
231
231
|
responses = []
|
232
232
|
n.times do|i|
|
233
|
-
responses[i] =
|
233
|
+
responses[i] = String.new
|
234
234
|
c = Curl::Easy.new($TEST_URL) do|curl|
|
235
235
|
curl.on_body{|data| responses[i] << data; data.size }
|
236
236
|
end
|
@@ -376,7 +376,7 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
376
376
|
attr_reader :buf
|
377
377
|
|
378
378
|
def t_method
|
379
|
-
@buf =
|
379
|
+
@buf = String.new
|
380
380
|
@m = Curl::Multi.new
|
381
381
|
10.times do|i|
|
382
382
|
c = Curl::Easy.new($TEST_URL)
|
@@ -422,8 +422,8 @@ class TestCurbCurlMulti < Test::Unit::TestCase
|
|
422
422
|
m = Curl::Multi.new
|
423
423
|
# add a few easy handles
|
424
424
|
requests.each do |url|
|
425
|
-
responses[url] =
|
426
|
-
responses["#{url}-header"] =
|
425
|
+
responses[url] = String.new
|
426
|
+
responses["#{url}-header"] = String.new
|
427
427
|
c = Curl::Easy.new(url) do|curl|
|
428
428
|
curl.follow_location = true
|
429
429
|
curl.on_header{|data| responses["#{url}-header"] << data; data.size }
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: curb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ross Bamford
|
8
8
|
- Todd A. Fisher
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2025-02-09 00:00:00.000000000 Z
|
13
12
|
dependencies: []
|
14
13
|
description: Curb (probably CUrl-RuBy or something) provides Ruby-language bindings
|
15
14
|
for the libcurl(3), a fully-featured client-side URL transfer library. cURL and
|
@@ -53,7 +52,6 @@ files:
|
|
53
52
|
- tests/bug_follow_redirect_288.rb
|
54
53
|
- tests/bug_instance_post_differs_from_class_post.rb
|
55
54
|
- tests/bug_issue102.rb
|
56
|
-
- tests/bug_issue277.rb
|
57
55
|
- tests/bug_multi_segfault.rb
|
58
56
|
- tests/bug_postfields_crash.rb
|
59
57
|
- tests/bug_postfields_crash2.rb
|
@@ -67,6 +65,7 @@ files:
|
|
67
65
|
- tests/tc_curl.rb
|
68
66
|
- tests/tc_curl_download.rb
|
69
67
|
- tests/tc_curl_easy.rb
|
68
|
+
- tests/tc_curl_easy_cookielist.rb
|
70
69
|
- tests/tc_curl_easy_resolve.rb
|
71
70
|
- tests/tc_curl_easy_setopt.rb
|
72
71
|
- tests/tc_curl_maxfilesize.rb
|
@@ -78,9 +77,8 @@ files:
|
|
78
77
|
- tests/unittests.rb
|
79
78
|
homepage: https://github.com/taf2/curb
|
80
79
|
licenses:
|
81
|
-
-
|
80
|
+
- Ruby
|
82
81
|
metadata: {}
|
83
|
-
post_install_message:
|
84
82
|
rdoc_options:
|
85
83
|
- "--main"
|
86
84
|
- README.markdown
|
@@ -98,8 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
98
96
|
- !ruby/object:Gem::Version
|
99
97
|
version: '0'
|
100
98
|
requirements: []
|
101
|
-
rubygems_version: 3.2
|
102
|
-
signing_key:
|
99
|
+
rubygems_version: 3.6.2
|
103
100
|
specification_version: 4
|
104
101
|
summary: Ruby libcurl bindings
|
105
102
|
test_files:
|
@@ -111,7 +108,6 @@ test_files:
|
|
111
108
|
- tests/bug_follow_redirect_288.rb
|
112
109
|
- tests/bug_instance_post_differs_from_class_post.rb
|
113
110
|
- tests/bug_issue102.rb
|
114
|
-
- tests/bug_issue277.rb
|
115
111
|
- tests/bug_multi_segfault.rb
|
116
112
|
- tests/bug_postfields_crash.rb
|
117
113
|
- tests/bug_postfields_crash2.rb
|
@@ -125,6 +121,7 @@ test_files:
|
|
125
121
|
- tests/tc_curl.rb
|
126
122
|
- tests/tc_curl_download.rb
|
127
123
|
- tests/tc_curl_easy.rb
|
124
|
+
- tests/tc_curl_easy_cookielist.rb
|
128
125
|
- tests/tc_curl_easy_resolve.rb
|
129
126
|
- tests/tc_curl_easy_setopt.rb
|
130
127
|
- tests/tc_curl_maxfilesize.rb
|
data/tests/bug_issue277.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
|
2
|
-
|
3
|
-
|
4
|
-
require 'curb'
|
5
|
-
|
6
|
-
class BugIssue102 < Test::Unit::TestCase
|
7
|
-
|
8
|
-
def test_gc_closewait
|
9
|
-
100.times do
|
10
|
-
responses = {}
|
11
|
-
requests = ["http://www.google.co.uk/", "http://www.ruby-lang.org/"]
|
12
|
-
m = Curl::Multi.new
|
13
|
-
# add a few easy handles
|
14
|
-
requests.each do |url|
|
15
|
-
responses[url] = ""
|
16
|
-
c = Curl::Easy.new(url) do|curl|
|
17
|
-
curl.follow_location = true
|
18
|
-
curl.on_body{|data| responses[url] << data; data.size }
|
19
|
-
curl.on_success {|easy| #puts "success, add more easy handles"
|
20
|
-
}
|
21
|
-
end
|
22
|
-
m.add(c)
|
23
|
-
end
|
24
|
-
|
25
|
-
m.perform do
|
26
|
-
#puts "idling... can do some work here"
|
27
|
-
end
|
28
|
-
GC.start
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
end
|