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.
@@ -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
- VALUE blk_result = rb_funcall(state->user_progress_blk,
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
- // Even though it is not documented, rb_thread_call_with_gvl is available even when
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
- /* List of active curl sessions */
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 Curl handle when the Session object is garbage collected. */
186
- void session_free(struct patron_curl_state *curl) {
187
- if (curl->handle) {
188
- curl_easy_cleanup(curl->handle);
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(curl);
184
+ session_close_debug_file(state);
193
185
 
194
- membuffer_destroy( &curl->header_buffer );
195
- membuffer_destroy( &curl->body_buffer );
186
+ membuffer_destroy(&state->header_buffer);
187
+ membuffer_destroy(&state->body_buffer);
196
188
 
197
- cs_list_remove(curl);
189
+ cs_list_remove(state);
198
190
 
199
- free(curl);
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* curl;
205
- VALUE obj = Data_Make_Struct(klass, struct patron_curl_state, NULL, session_free, curl);
206
-
207
- membuffer_init( &curl->header_buffer );
208
- membuffer_init( &curl->body_buffer );
209
- cs_list_append(curl);
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
- struct patron_curl_state* state = curl_easy_init();
278
- escaped = curl_easy_escape(state->handle,
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
- curl_easy_cleanup(state);
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
- struct patron_curl_state* state = curl_easy_init();
301
- unescaped = curl_easy_unescape(state->handle,
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
- curl_easy_cleanup(state);
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->handle;
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] = INT2NUM(code);
762
+ args[1] = LONG2NUM(code);
743
763
 
744
764
  curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &count);
745
- args[2] = INT2NUM(count);
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
- header_buffer = &state->header_buffer;
795
- body_buffer = &state->body_buffer;
796
-
797
- membuffer_clear(header_buffer);
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
- curl_easy_reset(state->handle);
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->handle;
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
- char* file_path = RSTRING_PTR(file);
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
- rb_define_method(cSession, "handle_request", session_handle_request, 1);
1012
- rb_define_method(cSession, "reset", session_reset, 0);
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
- rb_define_method(cSession, "add_cookie_file", add_cookie_file, 1);
1015
- rb_define_method(cSession, "set_debug_file", set_debug_file, 1);
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
 
@@ -34,8 +34,8 @@ module Patron
34
34
  :low_speed_time, :low_speed_limit, :progress_callback
35
35
  ]
36
36
 
37
- attr_reader *READER_VARS
38
- attr_writer *WRITER_VARS
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
  #
@@ -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.exists?(file_path) && !File.writable?(path.dirname)
147
+ if !File.exist?(file_path) && !File.writable?(path.dirname)
150
148
  raise ArgumentError, "Can't create file #{path} (permission error)"
151
- elsif File.exists?(file_path) && !File.writable?(file_path)
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
@@ -1,3 +1,3 @@
1
1
  module Patron
2
- VERSION = "0.13.1"
2
+ VERSION = "0.13.4"
3
3
  end
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 = ["Phillip Toland"]
11
- spec.email = ["phil.toland@gmail.com"]
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 RubyGemspec.org. To allow pushes either set the 'allowed_push_host'
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 pushespec."
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 environment.
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