patron 0.13.1 → 0.13.4
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 +5 -5
- data/.github/workflows/ci.yml +26 -0
- data/.travis.yml +10 -11
- data/CHANGELOG.md +21 -1
- data/Gemfile +14 -1
- data/README.md +92 -50
- data/ext/patron/extconf.rb +3 -4
- data/ext/patron/session_ext.c +111 -138
- data/lib/patron/request.rb +2 -2
- data/lib/patron/session.rb +2 -4
- data/lib/patron/version.rb +1 -1
- data/patron.gemspec +6 -14
- data/spec/patron_spec.rb +1 -1
- data/spec/session_spec.rb +119 -68
- data/spec/session_ssl_spec.rb +43 -40
- data/spec/spec_helper.rb +14 -2
- data/spec/support/config.ru +31 -15
- data/spec/support/fork.rb +70 -0
- data/spec/support/test_server.rb +12 -6
- metadata +13 -125
- /data/spec/{certs → support/certs}/cacert.pem +0 -0
- /data/spec/{certs → support/certs}/privkey.pem +0 -0
data/ext/patron/session_ext.c
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
#if defined(USE_TBR) && defined(HAVE_THREAD_H)
|
3
2
|
#include <ruby/thread.h>
|
4
|
-
#endif
|
5
3
|
#include <sys/stat.h>
|
6
4
|
#include <curl/curl.h>
|
7
5
|
#include "membuffer.h"
|
@@ -29,6 +27,8 @@ static VALUE eAborted = Qnil;
|
|
29
27
|
|
30
28
|
struct patron_curl_state {
|
31
29
|
CURL* handle;
|
30
|
+
CURL* base_handle;
|
31
|
+
CURLSH* share;
|
32
32
|
char* upload_buf;
|
33
33
|
FILE* download_file;
|
34
34
|
FILE* debug_file;
|
@@ -77,7 +77,7 @@ static size_t file_write_handler(void* stream, size_t size, size_t nmemb, FILE*
|
|
77
77
|
static int call_user_rb_progress_blk(void* vd_curl_state) {
|
78
78
|
struct patron_curl_state* state = (struct patron_curl_state*)vd_curl_state;
|
79
79
|
// Invoke the block with the array
|
80
|
-
|
80
|
+
rb_funcall(state->user_progress_blk,
|
81
81
|
rb_intern("call"), 4,
|
82
82
|
LONG2NUM(state->dltotal),
|
83
83
|
LONG2NUM(state->dlnow),
|
@@ -103,15 +103,7 @@ static int session_progress_handler(void* clientp, size_t dltotal, size_t dlnow,
|
|
103
103
|
// `call_user_rb_progress_blk`. TODO: use the retval of that proc
|
104
104
|
// to permit premature abort
|
105
105
|
if(RTEST(state->user_progress_blk)) {
|
106
|
-
|
107
|
-
// rb_thread_call_without_gvl is not. See https://bugs.ruby-lang.org/issues/5543#note-4
|
108
|
-
// > rb_thread_call_with_gvl() is globally-visible (but not in headers)
|
109
|
-
// > for 1.9.3: https://bugs.ruby-lang.org/issues/4328
|
110
|
-
#if (defined(HAVE_TBR) || defined(HAVE_TCWOGVL)) && defined(USE_TBR)
|
111
|
-
rb_thread_call_with_gvl((void *(*)(void *)) call_user_rb_progress_blk, (void*)state);
|
112
|
-
#else
|
113
|
-
call_user_rb_progress_blk((void*)state);
|
114
|
-
#endif
|
106
|
+
rb_thread_call_with_gvl((void *(*)(void *)) call_user_rb_progress_blk, (void*)state);
|
115
107
|
}
|
116
108
|
|
117
109
|
// Set the interrupt if the download byte limit has been reached
|
@@ -129,9 +121,10 @@ static int session_progress_handler(void* clientp, size_t dltotal, size_t dlnow,
|
|
129
121
|
}
|
130
122
|
|
131
123
|
|
132
|
-
|
133
|
-
|
134
|
-
|
124
|
+
/*
|
125
|
+
List of active curl sessions, used exclusively to be able to set interrupts
|
126
|
+
for all of them if the Ruby interpreter gets shut down with libCURL requests still in flight.
|
127
|
+
*/
|
135
128
|
struct patron_curl_state_list {
|
136
129
|
struct patron_curl_state *state;
|
137
130
|
struct patron_curl_state_list *next;
|
@@ -163,6 +156,7 @@ static void cs_list_remove(struct patron_curl_state *state) {
|
|
163
156
|
}
|
164
157
|
}
|
165
158
|
|
159
|
+
/* Gets attached to at_exit of the Ruby process to be able to abort all running libCURL requests and quit */
|
166
160
|
static void cs_list_interrupt(VALUE data) {
|
167
161
|
UNUSED_ARGUMENT(data);
|
168
162
|
|
@@ -182,31 +176,64 @@ static void session_close_debug_file(struct patron_curl_state *curl) {
|
|
182
176
|
curl->debug_file = NULL;
|
183
177
|
}
|
184
178
|
|
185
|
-
/* Cleans up the
|
186
|
-
void session_free(struct patron_curl_state *
|
187
|
-
|
188
|
-
|
189
|
-
curl->handle = NULL;
|
190
|
-
}
|
179
|
+
/* Cleans up the patron_curl_state data when the Session object is garbage collected. */
|
180
|
+
void session_free(struct patron_curl_state *state) {
|
181
|
+
curl_easy_cleanup(state->base_handle);
|
182
|
+
curl_share_cleanup(state->share);
|
191
183
|
|
192
|
-
session_close_debug_file(
|
184
|
+
session_close_debug_file(state);
|
193
185
|
|
194
|
-
membuffer_destroy(
|
195
|
-
membuffer_destroy(
|
186
|
+
membuffer_destroy(&state->header_buffer);
|
187
|
+
membuffer_destroy(&state->body_buffer);
|
196
188
|
|
197
|
-
cs_list_remove(
|
189
|
+
cs_list_remove(state);
|
198
190
|
|
199
|
-
free(
|
191
|
+
free(state);
|
200
192
|
}
|
201
193
|
|
202
194
|
/* Allocates patron_curl_state data needed for a new Session object. */
|
203
195
|
VALUE session_alloc(VALUE klass) {
|
204
|
-
struct patron_curl_state*
|
205
|
-
VALUE obj = Data_Make_Struct(klass, struct patron_curl_state, NULL, session_free,
|
206
|
-
|
207
|
-
membuffer_init(
|
208
|
-
membuffer_init(
|
209
|
-
cs_list_append(
|
196
|
+
struct patron_curl_state* state;
|
197
|
+
VALUE obj = Data_Make_Struct(klass, struct patron_curl_state, NULL, session_free, state);
|
198
|
+
|
199
|
+
membuffer_init(&state->header_buffer);
|
200
|
+
membuffer_init(&state->body_buffer);
|
201
|
+
cs_list_append(state);
|
202
|
+
|
203
|
+
/*
|
204
|
+
Eagerly initialize the curl handle. We initialize it only once and store it
|
205
|
+
in the struct until the Session object gets garbage-collected in session_free(). This allows libCURL to
|
206
|
+
reuse the TCP connection and can speed things up if the same resource - like a backend service -
|
207
|
+
gets accessed over and over with requests.
|
208
|
+
*/
|
209
|
+
state->share = curl_share_init();
|
210
|
+
curl_share_setopt(state->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_COOKIE);
|
211
|
+
curl_share_setopt(state->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
|
212
|
+
curl_share_setopt(state->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
|
213
|
+
curl_share_setopt(state->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
|
214
|
+
curl_share_setopt(state->share, CURLSHOPT_SHARE, CURL_LOCK_DATA_PSL);
|
215
|
+
state->base_handle = curl_easy_init();
|
216
|
+
curl_easy_setopt(state->base_handle, CURLOPT_SHARE, state->share);
|
217
|
+
curl_easy_setopt(state->base_handle, CURLOPT_WRITEFUNCTION, &session_write_handler);
|
218
|
+
curl_easy_setopt(state->base_handle, CURLOPT_WRITEDATA, &state->body_buffer);
|
219
|
+
curl_easy_setopt(state->base_handle, CURLOPT_HEADERFUNCTION, &session_write_handler);
|
220
|
+
curl_easy_setopt(state->base_handle, CURLOPT_HEADERDATA, &state->header_buffer);
|
221
|
+
curl_easy_setopt(state->base_handle, CURLOPT_NOSIGNAL, 1);
|
222
|
+
curl_easy_setopt(state->base_handle, CURLOPT_NOPROGRESS, 0);
|
223
|
+
#if LIBCURL_VERSION_NUM >= 0x072000
|
224
|
+
/* this is libCURLv7.32.0 or later, supports CURLOPT_XFERINFOFUNCTION */
|
225
|
+
curl_easy_setopt(state->base_handle, CURLOPT_XFERINFOFUNCTION, &session_progress_handler);
|
226
|
+
#else
|
227
|
+
curl_easy_setopt(state->base_handle, CURLOPT_PROGRESSFUNCTION, &session_progress_handler);
|
228
|
+
#endif
|
229
|
+
curl_easy_setopt(state->base_handle, CURLOPT_PROGRESSDATA, state);
|
230
|
+
#ifdef CURLPROTO_HTTP
|
231
|
+
// Security: do not allow Curl to go looking on gopher/SMTP etc.
|
232
|
+
// Must prevent situations like this:
|
233
|
+
// https://hackerone.com/reports/115748
|
234
|
+
curl_easy_setopt(state->base_handle, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
235
|
+
curl_easy_setopt(state->base_handle, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
236
|
+
#endif
|
210
237
|
|
211
238
|
return obj;
|
212
239
|
}
|
@@ -215,25 +242,9 @@ VALUE session_alloc(VALUE klass) {
|
|
215
242
|
static struct patron_curl_state* get_patron_curl_state(VALUE self) {
|
216
243
|
struct patron_curl_state* state;
|
217
244
|
Data_Get_Struct(self, struct patron_curl_state, state);
|
218
|
-
|
219
|
-
if (NULL == state->handle) {
|
220
|
-
state->handle = curl_easy_init();
|
221
|
-
curl_easy_setopt(state->handle, CURLOPT_NOSIGNAL, 1);
|
222
|
-
curl_easy_setopt(state->handle, CURLOPT_NOPROGRESS, 0);
|
223
|
-
#if LIBCURL_VERSION_NUM >= 0x072000
|
224
|
-
/* this is libCURLv7.32.0 or later, supports CURLOPT_XFERINFOFUNCTION */
|
225
|
-
curl_easy_setopt(state->handle, CURLOPT_XFERINFOFUNCTION, &session_progress_handler);
|
226
|
-
#else
|
227
|
-
curl_easy_setopt(state->handle, CURLOPT_PROGRESSFUNCTION, &session_progress_handler);
|
228
|
-
#endif
|
229
|
-
|
230
|
-
curl_easy_setopt(state->handle, CURLOPT_PROGRESSDATA, state);
|
231
|
-
}
|
232
|
-
|
233
245
|
return state;
|
234
246
|
}
|
235
247
|
|
236
|
-
|
237
248
|
/*----------------------------------------------------------------------------*/
|
238
249
|
/* Method implementations */
|
239
250
|
|
@@ -274,13 +285,22 @@ static VALUE session_escape(VALUE self, VALUE value) {
|
|
274
285
|
char* escaped = NULL;
|
275
286
|
VALUE retval = Qnil;
|
276
287
|
|
277
|
-
|
278
|
-
|
288
|
+
#if LIBCURL_VERSION_NUM >= 0x075200
|
289
|
+
/* this is libCURLv7.82.0 or later, the curl parameter is ignored */
|
290
|
+
CURL *curl = NULL;
|
291
|
+
#else
|
292
|
+
CURL* curl = curl_easy_init();
|
293
|
+
#endif
|
294
|
+
escaped = curl_easy_escape(curl,
|
279
295
|
RSTRING_PTR(string),
|
280
296
|
(int) RSTRING_LEN(string));
|
281
297
|
|
282
298
|
retval = rb_str_new2(escaped);
|
283
|
-
|
299
|
+
#if LIBCURL_VERSION_NUM >= 0x075200
|
300
|
+
/* this is libCURLv7.82.0 or later, the curl parameter is ignored */
|
301
|
+
#else
|
302
|
+
curl_easy_cleanup(curl);
|
303
|
+
#endif
|
284
304
|
curl_free(escaped);
|
285
305
|
|
286
306
|
return retval;
|
@@ -297,15 +317,24 @@ static VALUE session_unescape(VALUE self, VALUE value) {
|
|
297
317
|
char* unescaped = NULL;
|
298
318
|
VALUE retval = Qnil;
|
299
319
|
|
300
|
-
|
301
|
-
|
320
|
+
#if LIBCURL_VERSION_NUM >= 0x075200
|
321
|
+
/* this is libCURLv7.82.0 or later, the curl parameter is ignored */
|
322
|
+
CURL *curl = NULL;
|
323
|
+
#else
|
324
|
+
CURL *curl = curl_easy_init();
|
325
|
+
#endif
|
326
|
+
unescaped = curl_easy_unescape(curl,
|
302
327
|
RSTRING_PTR(string),
|
303
328
|
(int) RSTRING_LEN(string),
|
304
329
|
NULL);
|
305
330
|
|
306
331
|
retval = rb_str_new2(unescaped);
|
307
332
|
curl_free(unescaped);
|
308
|
-
|
333
|
+
#if LIBCURL_VERSION_NUM >= 0x075200
|
334
|
+
/* this is libCURLv7.82.0 or later, the curl parameter is ignored */
|
335
|
+
#else
|
336
|
+
curl_easy_cleanup(curl);
|
337
|
+
#endif
|
309
338
|
|
310
339
|
return retval;
|
311
340
|
}
|
@@ -431,7 +460,7 @@ static void set_request_body(struct patron_curl_state* state, VALUE stringable_o
|
|
431
460
|
*/
|
432
461
|
static void set_options_from_request(VALUE self, VALUE request) {
|
433
462
|
struct patron_curl_state* state = get_patron_curl_state(self);
|
434
|
-
CURL* curl = state->
|
463
|
+
CURL* curl = curl_easy_duphandle(state->base_handle);
|
435
464
|
|
436
465
|
ID action = Qnil;
|
437
466
|
VALUE headers = Qnil;
|
@@ -452,6 +481,9 @@ static void set_options_from_request(VALUE self, VALUE request) {
|
|
452
481
|
VALUE download_byte_limit = rb_funcall(request, rb_intern("download_byte_limit"), 0);
|
453
482
|
VALUE maybe_progress_proc = rb_funcall(request, rb_intern("progress_callback"), 0);
|
454
483
|
|
484
|
+
state->handle = curl;
|
485
|
+
curl_easy_setopt(curl, CURLOPT_SHARE, state->share);
|
486
|
+
|
455
487
|
if (RTEST(download_byte_limit)) {
|
456
488
|
state->download_byte_limit = FIX2INT(download_byte_limit);
|
457
489
|
} else {
|
@@ -473,7 +505,7 @@ static void set_options_from_request(VALUE self, VALUE request) {
|
|
473
505
|
}
|
474
506
|
|
475
507
|
action = SYM2ID(action_name);
|
476
|
-
if(rb_funcall(request, rb_intern("force_ipv4"), 0)) {
|
508
|
+
if (RTEST(rb_funcall(request, rb_intern("force_ipv4"), 0))) {
|
477
509
|
curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
478
510
|
}
|
479
511
|
if (action == rb_intern("get")) {
|
@@ -576,13 +608,6 @@ static void set_options_from_request(VALUE self, VALUE request) {
|
|
576
608
|
}
|
577
609
|
curl_easy_setopt(curl, CURLOPT_URL, StringValuePtr(url));
|
578
610
|
|
579
|
-
#ifdef CURLPROTO_HTTP
|
580
|
-
// Security: do not allow Curl to go looking on gopher/SMTP etc.
|
581
|
-
// Must prevent situations like this:
|
582
|
-
// https://hackerone.com/reports/115748
|
583
|
-
curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
584
|
-
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
585
|
-
#endif
|
586
611
|
|
587
612
|
timeout = rb_funcall(request, rb_intern("timeout"), 0);
|
588
613
|
if (RTEST(timeout)) {
|
@@ -720,11 +745,6 @@ static void set_options_from_request(VALUE self, VALUE request) {
|
|
720
745
|
if (RTEST(buffer_size)) {
|
721
746
|
curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, NUM2LONG(buffer_size));
|
722
747
|
}
|
723
|
-
|
724
|
-
if(state->debug_file) {
|
725
|
-
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
726
|
-
curl_easy_setopt(curl, CURLOPT_STDERR, state->debug_file);
|
727
|
-
}
|
728
748
|
}
|
729
749
|
|
730
750
|
/* Use the info in a Curl handle to create a new Response object. */
|
@@ -739,10 +759,10 @@ static VALUE create_response(VALUE self, CURL* curl, VALUE header_buffer, VALUE
|
|
739
759
|
args[0] = rb_str_new2(effective_url);
|
740
760
|
|
741
761
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code);
|
742
|
-
args[1] =
|
762
|
+
args[1] = LONG2NUM(code);
|
743
763
|
|
744
764
|
curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &count);
|
745
|
-
args[2] =
|
765
|
+
args[2] = LONG2NUM(count);
|
746
766
|
|
747
767
|
args[3] = header_buffer;
|
748
768
|
args[4] = body_buffer;
|
@@ -785,48 +805,19 @@ void session_ubf_abort(void* patron_state) {
|
|
785
805
|
static VALUE perform_request(VALUE self) {
|
786
806
|
struct patron_curl_state *state = get_patron_curl_state(self);
|
787
807
|
CURL* curl = state->handle;
|
788
|
-
membuffer* header_buffer = NULL;
|
789
|
-
membuffer* body_buffer = NULL;
|
790
808
|
CURLcode ret = 0;
|
791
809
|
|
792
810
|
state->interrupt = 0; /* clear the interrupt flag */
|
793
811
|
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
membuffer_clear(body_buffer);
|
799
|
-
|
800
|
-
/* headers */
|
801
|
-
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &session_write_handler);
|
802
|
-
curl_easy_setopt(curl, CURLOPT_HEADERDATA, header_buffer);
|
803
|
-
|
804
|
-
/* body */
|
805
|
-
if (!state->download_file) {
|
806
|
-
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &session_write_handler);
|
807
|
-
curl_easy_setopt(curl, CURLOPT_WRITEDATA, body_buffer);
|
808
|
-
}
|
809
|
-
|
810
|
-
#if (defined(HAVE_TBR) || defined(HAVE_TCWOGVL)) && defined(USE_TBR)
|
811
|
-
#if defined(HAVE_TCWOGVL)
|
812
|
-
ret = (CURLcode) rb_thread_call_without_gvl(
|
813
|
-
(void *(*)(void *)) curl_easy_perform, curl,
|
814
|
-
session_ubf_abort, (void*)state
|
815
|
-
);
|
816
|
-
#else
|
817
|
-
ret = (CURLcode) rb_thread_blocking_region(
|
818
|
-
(rb_blocking_function_t*) curl_easy_perform, curl,
|
819
|
-
session_ubf_abort, (void*)state
|
820
|
-
);
|
821
|
-
#endif
|
822
|
-
#else
|
823
|
-
ret = curl_easy_perform(curl);
|
824
|
-
#endif
|
812
|
+
ret = (CURLcode) rb_thread_call_without_gvl(
|
813
|
+
(void *(*)(void *)) curl_easy_perform, curl,
|
814
|
+
session_ubf_abort, (void*)state
|
815
|
+
);
|
825
816
|
|
826
817
|
if (CURLE_OK == ret) {
|
827
|
-
VALUE header_str = membuffer_to_rb_str(header_buffer);
|
818
|
+
VALUE header_str = membuffer_to_rb_str(&state->header_buffer);
|
828
819
|
VALUE body_str = Qnil;
|
829
|
-
if (!state->download_file) { body_str = membuffer_to_rb_str(body_buffer); }
|
820
|
+
if (!state->download_file) { body_str = membuffer_to_rb_str(&state->body_buffer); }
|
830
821
|
|
831
822
|
curl_easy_setopt(curl, CURLOPT_COOKIELIST, "FLUSH"); // Flush cookies to the cookie jar
|
832
823
|
|
@@ -841,16 +832,19 @@ static VALUE perform_request(VALUE self) {
|
|
841
832
|
*/
|
842
833
|
static VALUE cleanup(VALUE self) {
|
843
834
|
struct patron_curl_state *state = get_patron_curl_state(self);
|
844
|
-
|
835
|
+
curl_easy_cleanup(state->handle);
|
845
836
|
|
846
837
|
if (state->headers) {
|
847
838
|
curl_slist_free_all(state->headers);
|
848
839
|
state->headers = NULL;
|
849
840
|
}
|
841
|
+
membuffer_clear(&state->header_buffer);
|
850
842
|
|
851
843
|
if (state->download_file) {
|
852
844
|
fclose(state->download_file);
|
853
845
|
state->download_file = NULL;
|
846
|
+
} else {
|
847
|
+
membuffer_clear(&state->body_buffer);
|
854
848
|
}
|
855
849
|
|
856
850
|
if (state->request_body_file) {
|
@@ -887,33 +881,9 @@ static VALUE session_handle_request(VALUE self, VALUE request) {
|
|
887
881
|
return rb_ensure(&perform_request, self, &cleanup, self);
|
888
882
|
}
|
889
883
|
|
890
|
-
/*
|
891
|
-
* FIXME: figure out how this method should be used at all given Session is not multithreaded.
|
892
|
-
* FIXME: also: what is the difference with `interrupt()` and also relationship with `cleanup()`?
|
893
|
-
* Reset the underlying cURL session. This effectively closes all open
|
894
|
-
* connections and disables debug output. There is no need to call this method
|
895
|
-
* manually after performing a request, since cleanup is performed automatically
|
896
|
-
* but the method can be used from another thread
|
897
|
-
* to abort a request currently in progress.
|
898
|
-
*
|
899
|
-
* @return self
|
900
|
-
*/
|
901
|
-
static VALUE session_reset(VALUE self) {
|
902
|
-
struct patron_curl_state *state;
|
903
|
-
Data_Get_Struct(self, struct patron_curl_state, state);
|
904
|
-
|
905
|
-
if (NULL != state->handle) {
|
906
|
-
cleanup(self);
|
907
|
-
curl_easy_cleanup(state->handle);
|
908
|
-
state->handle = NULL;
|
909
|
-
session_close_debug_file(state);
|
910
|
-
}
|
911
|
-
|
912
|
-
return self;
|
913
|
-
}
|
914
|
-
|
915
884
|
/* Interrupt any currently executing request. This will cause the current
|
916
|
-
* request to error and raise an exception.
|
885
|
+
* request to error and raise an exception. The method can be called from another thread to
|
886
|
+
* abort the request in-flight.
|
917
887
|
*
|
918
888
|
* @return [void] This method always raises
|
919
889
|
*/
|
@@ -934,7 +904,7 @@ static VALUE session_interrupt(VALUE self) {
|
|
934
904
|
*/
|
935
905
|
static VALUE add_cookie_file(VALUE self, VALUE file) {
|
936
906
|
struct patron_curl_state *state = get_patron_curl_state(self);
|
937
|
-
CURL* curl = state->
|
907
|
+
CURL* curl = state->base_handle;
|
938
908
|
char* file_path = NULL;
|
939
909
|
|
940
910
|
// FIXME: http://websystemsengineering.blogspot.nl/2013/03/curloptcookiefile-vs-curloptcookiejar.html
|
@@ -955,7 +925,8 @@ static VALUE add_cookie_file(VALUE self, VALUE file) {
|
|
955
925
|
*/
|
956
926
|
static VALUE set_debug_file(VALUE self, VALUE file) {
|
957
927
|
struct patron_curl_state *state = get_patron_curl_state(self);
|
958
|
-
|
928
|
+
CURL *curl = state->base_handle;
|
929
|
+
char *file_path = RSTRING_PTR(file);
|
959
930
|
|
960
931
|
session_close_debug_file(state);
|
961
932
|
|
@@ -964,6 +935,8 @@ static VALUE set_debug_file(VALUE self, VALUE file) {
|
|
964
935
|
} else {
|
965
936
|
state->debug_file = stderr;
|
966
937
|
}
|
938
|
+
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
939
|
+
curl_easy_setopt(curl, CURLOPT_STDERR, state->debug_file);
|
967
940
|
|
968
941
|
return self;
|
969
942
|
}
|
@@ -1008,11 +981,11 @@ void Init_session_ext() {
|
|
1008
981
|
rb_define_singleton_method(cSession, "unescape", session_unescape, 1);
|
1009
982
|
rb_define_method(cSession, "unescape", session_unescape, 1);
|
1010
983
|
|
1011
|
-
|
1012
|
-
rb_define_method(cSession, "reset",
|
984
|
+
rb_define_private_method(cSession, "handle_request", session_handle_request, 1);
|
985
|
+
rb_define_method(cSession, "reset", session_interrupt, 0);
|
1013
986
|
rb_define_method(cSession, "interrupt", session_interrupt, 0);
|
1014
|
-
|
1015
|
-
|
987
|
+
rb_define_private_method(cSession, "add_cookie_file", add_cookie_file, 1);
|
988
|
+
rb_define_private_method(cSession, "set_debug_file", set_debug_file, 1);
|
1016
989
|
rb_define_alias(cSession, "urlencode", "escape");
|
1017
990
|
rb_define_alias(cSession, "urldecode", "unescape");
|
1018
991
|
|
data/lib/patron/request.rb
CHANGED
@@ -34,8 +34,8 @@ module Patron
|
|
34
34
|
:low_speed_time, :low_speed_limit, :progress_callback
|
35
35
|
]
|
36
36
|
|
37
|
-
attr_reader
|
38
|
-
attr_writer
|
37
|
+
attr_reader(*READER_VARS)
|
38
|
+
attr_writer(*WRITER_VARS)
|
39
39
|
|
40
40
|
# Set the type of authentication to use for this request.
|
41
41
|
#
|
data/lib/patron/session.rb
CHANGED
@@ -103,8 +103,6 @@ module Patron
|
|
103
103
|
# @see low_speed_time
|
104
104
|
attr_accessor :low_speed_limit
|
105
105
|
|
106
|
-
private :handle_request, :add_cookie_file, :set_debug_file
|
107
|
-
|
108
106
|
# @return [#call, nil] callable object that will be called with 4 arguments
|
109
107
|
# during request/response execution - `dltotal`, `dlnow`, `ultotal`, `ulnow`.
|
110
108
|
# All these arguments are in bytes.
|
@@ -146,9 +144,9 @@ module Patron
|
|
146
144
|
if file_path
|
147
145
|
path = Pathname(file_path).expand_path
|
148
146
|
|
149
|
-
if !File.
|
147
|
+
if !File.exist?(file_path) && !File.writable?(path.dirname)
|
150
148
|
raise ArgumentError, "Can't create file #{path} (permission error)"
|
151
|
-
elsif File.
|
149
|
+
elsif File.exist?(file_path) && !File.writable?(file_path)
|
152
150
|
raise ArgumentError, "Can't read or write file #{path} (permission error)"
|
153
151
|
end
|
154
152
|
else
|
data/lib/patron/version.rb
CHANGED
data/patron.gemspec
CHANGED
@@ -6,23 +6,23 @@ require 'patron/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "patron"
|
8
8
|
spec.version = Patron::VERSION
|
9
|
+
spec.licenses = ["MIT"]
|
9
10
|
spec.platform = Gem::Platform::RUBY
|
10
|
-
spec.authors = ["
|
11
|
-
spec.email = ["
|
11
|
+
spec.authors = ["Aeryn Riley Dowling-Toland"]
|
12
|
+
spec.email = ["aeryn.toland@gmail.com"]
|
12
13
|
spec.homepage = "https://github.com/toland/patron"
|
13
14
|
spec.summary = "Patron HTTP Client"
|
14
15
|
spec.description = "Ruby HTTP client library based on libcurl"
|
15
16
|
|
16
|
-
# Prevent pushing this gem to
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
18
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
19
|
if spec.respond_to?(:metadata)
|
19
20
|
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
20
21
|
else
|
21
|
-
raise "RubyGems 2.0 or newer is required to protect against public gem
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
22
23
|
end
|
23
24
|
|
24
25
|
spec.required_rubygems_version = ">= 1.2.0"
|
25
|
-
spec.rubyforge_project = "patron"
|
26
26
|
|
27
27
|
spec.files = `git ls-files -z`.split("\x0")
|
28
28
|
spec.bindir = "exe"
|
@@ -31,16 +31,8 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.extensions = ["ext/patron/extconf.rb"]
|
32
32
|
spec.post_install_message = %q{
|
33
33
|
Thank you for installing Patron. On OSX, make sure you are using libCURL with OpenSSL.
|
34
|
-
SecureTransport-based builds might cause crashes in forking
|
34
|
+
SecureTransport-based builds might cause crashes in forking environments.
|
35
35
|
|
36
36
|
For more info see https://github.com/curl/curl/issues/788
|
37
37
|
}
|
38
|
-
spec.add_development_dependency "rake", "~> 10"
|
39
|
-
spec.add_development_dependency "bundler", ">= 1"
|
40
|
-
spec.add_development_dependency "rspec", ">= 2.3.0"
|
41
|
-
spec.add_development_dependency "simplecov", "~> 0.10"
|
42
|
-
spec.add_development_dependency "yard", "~> 0.9.11"
|
43
|
-
spec.add_development_dependency "rack", "~> 1"
|
44
|
-
spec.add_development_dependency "puma", '~> 3.11'
|
45
|
-
spec.add_development_dependency "rake-compiler"
|
46
38
|
end
|
data/spec/patron_spec.rb
CHANGED
@@ -10,7 +10,7 @@ describe Patron do
|
|
10
10
|
|
11
11
|
it "should return the version number of the Patron library" do
|
12
12
|
version = Patron.version
|
13
|
-
expect(version).to match(%r|^\d+.\d+.\d
|
13
|
+
expect(version).to match(%r|^\d+.\d+.\d+(\.\w+\.\d+)?$|)
|
14
14
|
end
|
15
15
|
|
16
16
|
it "should return the version string of the libcurl library" do
|