patron 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9e89c04473c18143c350dcbbbf6f98b1c66b2e7e
4
- data.tar.gz: 5a019a6f724c14056f949eb4fafb538454b959c6
3
+ metadata.gz: f6d71dc0eaded4e48a770c409f82a571a4f77151
4
+ data.tar.gz: cdf33d99ce93e86f79d7889860be83f2cb87ba94
5
5
  SHA512:
6
- metadata.gz: 6468281adbd09ad4cbc02eaaa64c36926e108ecd6c9b7a38ffcf8223e5c9930147197c858dac1d30b0f728ece4065f97f32604e07f4016036363b5e110f30ce6
7
- data.tar.gz: 897c874cf04b2f3d8fa5e327a5cc78bd86d3ba4a6b27828812c67bc3433cdc0d4c4e6bad266ef655a9349d8f7d711cd95d60bd8c166ede3c8456c788fcc21197
6
+ metadata.gz: c7d7a4a3832c5b9774cc8171b51e69c15fba9d9d05a050b0ecda76c437ee3db9bb87aad218dfd3f34b54bb34e99612f410e56a0ab21714f5010b3fdb381bbd01
7
+ data.tar.gz: 72dddcb493902c90deb114655c61a247a7927f2be526c212a8294be5c3a0bb144fd92fb666450a84cd83c249a91f2b105d9508caf87210b432acec5b85ae496f
data/.travis.yml CHANGED
@@ -3,5 +3,7 @@ rvm:
3
3
  - 2.1.5
4
4
  - 2.2.2
5
5
  - 2.3.0
6
+ - 2.4.1
6
7
  sudo: false
8
+ dist: trusty
7
9
  cache: bundler
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ### 0.9.1
2
+
3
+ * Added ssl_version options `TLSv1_1`, `TLSv1_2`, `TLSv1_3` for explicitly forcing the SSL version
4
+ * requires the appropriate versions of libCURL and OpenSSL installed to support these new options
5
+ * reference: https://curl.haxx.se/libcurl/c/CURLOPT_SSLVERSION.html
6
+ * Added a new `:http_version` option with `HTTPv1_1` and `HTTPv2_0` values to explicitly set the HTTP version of HTTP/1.1 or HTTP/2.0
7
+ * requires the appropriate versions of libCURL and OpenSSL installed to support these new options
8
+ * reference: https://curl.haxx.se/libcurl/c/CURLOPT_HTTP_VERSION.html
9
+ * Updates the gem release procedure for more convenience, using the updated Rubygems.org tasks
10
+ * Update a few minor dependencies and documentation to be Ruby 2.4.1-compatible, add 2.4.1. to Travis CI matrix
11
+ * Add `Session#download_byte_limit` for limiting the permitted download size.
12
+ This can be very useful in dealing with untrusted download sources, which might attempt
13
+ to send very large responses that would overwhelm the receiving client.
14
+ * Add `Patron.libcurl_version_exact` which returns a triplet of major, minor and patch libCURL version numbers. This can be used
15
+ for more fine-grained matching when using some more esoteric Curl features which might not necessarily be available on libCURL
16
+ Patron has been linked against.
17
+
1
18
  ### 0.8.0
2
19
 
3
20
  * Add `Response#inspectable_body`, `Response#decoded_body`. `decoded_body` will atempt to decode
data/Gemfile CHANGED
@@ -1,2 +1,4 @@
1
1
  source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in patron.gemspec
2
4
  gemspec
data/Gemfile.lock CHANGED
@@ -1,14 +1,14 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- patron (0.8.0)
4
+ patron (0.9.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
9
  diff-lcs (1.2.5)
10
10
  docile (1.1.5)
11
- json (1.8.3)
11
+ json (2.1.0)
12
12
  rake (10.4.2)
13
13
  rake-compiler (0.9.5)
14
14
  rake
@@ -25,23 +25,24 @@ GEM
25
25
  diff-lcs (>= 1.2.0, < 2.0)
26
26
  rspec-support (~> 3.3.0)
27
27
  rspec-support (3.3.0)
28
- simplecov (0.10.0)
28
+ simplecov (0.14.1)
29
29
  docile (~> 1.1.0)
30
- json (~> 1.8)
30
+ json (>= 1.8, < 3)
31
31
  simplecov-html (~> 0.10.0)
32
- simplecov-html (0.10.0)
32
+ simplecov-html (0.10.1)
33
33
  yard (0.8.7.6)
34
34
 
35
35
  PLATFORMS
36
36
  ruby
37
37
 
38
38
  DEPENDENCIES
39
- bundler (>= 1.0.0)
39
+ bundler (>= 1)
40
40
  patron!
41
- rake-compiler (>= 0.7.5)
41
+ rake (~> 10)
42
+ rake-compiler
42
43
  rspec (>= 2.3.0)
43
- simplecov (>= 0.10.0)
44
+ simplecov (~> 0.10)
44
45
  yard (~> 0.8)
45
46
 
46
47
  BUNDLED WITH
47
- 1.11.2
48
+ 1.14.6
data/Rakefile CHANGED
@@ -24,17 +24,17 @@
24
24
  require 'rake/clean'
25
25
  require 'rake/extensiontask'
26
26
  require 'rspec/core/rake_task'
27
- require 'bundler'
27
+ require "bundler/gem_tasks"
28
28
  require 'yard'
29
29
 
30
+ RSpec::Core::RakeTask.new(:spec)
31
+
30
32
  Rake::ExtensionTask.new do |ext|
31
33
  ext.name = 'session_ext' # indicate the name of the extension.
32
34
  ext.ext_dir = 'ext/patron' # search for 'hello_world' inside it.
33
35
  ext.lib_dir = 'lib/patron' # put binaries into this folder.
34
36
  end
35
37
 
36
- Bundler::GemHelper.install_tasks
37
-
38
38
  CLEAN.include FileList["ext/patron/*"].exclude(/^.*\.(rb|c|h)$/)
39
39
  CLOBBER.include %w( doc coverage pkg )
40
40
 
@@ -50,12 +50,5 @@ YARD::Rake::YardocTask.new do |t|
50
50
  t.stats_options = ['--list-undoc']
51
51
  end
52
52
 
53
- desc "Run specs"
54
- RSpec::Core::RakeTask.new do |t|
55
- t.rspec_opts = %w( --colour --format progress )
56
- t.pattern = 'spec/**/*_spec.rb'
57
- end
58
-
59
- task :spec => [:compile]
60
-
61
- task :default => :spec
53
+ task :default => [:clobber, :compile, :spec]
54
+ task :build => [:clobber] # Make sure no binaries end up in the gem
@@ -32,6 +32,8 @@
32
32
  #include "sglib.h" /* Simple Generic Library -> http://sglib.sourceforge.net */
33
33
 
34
34
  #define UNUSED_ARGUMENT(x) (void)x
35
+ #define INTERRUPT_ABORT 1
36
+ #define INTERRUPT_DOWNLOAD_OVERFLOW 2
35
37
 
36
38
  static VALUE mPatron = Qnil;
37
39
  static VALUE mProxyType = Qnil;
@@ -40,15 +42,16 @@ static VALUE cRequest = Qnil;
40
42
  static VALUE ePatronError = Qnil;
41
43
  static VALUE eUnsupportedProtocol = Qnil;
42
44
  static VALUE eUnsupportedSSLVersion = Qnil;
45
+ static VALUE eUnsupportedHTTPVersion = Qnil;
43
46
  static VALUE eURLFormatError = Qnil;
44
47
  static VALUE eHostResolutionError = Qnil;
45
48
  static VALUE eConnectionFailed = Qnil;
46
49
  static VALUE ePartialFileError = Qnil;
47
50
  static VALUE eTimeoutError = Qnil;
48
51
  static VALUE eTooManyRedirects = Qnil;
52
+ static VALUE eAborted = Qnil;
49
53
 
50
-
51
- struct curl_state {
54
+ struct patron_curl_state {
52
55
  CURL* handle;
53
56
  char* upload_buf;
54
57
  FILE* download_file;
@@ -60,6 +63,7 @@ struct curl_state {
60
63
  struct curl_httppost* last;
61
64
  membuffer header_buffer;
62
65
  membuffer body_buffer;
66
+ size_t download_byte_limit;
63
67
  int interrupt;
64
68
  };
65
69
 
@@ -78,17 +82,39 @@ static size_t session_write_handler(char* stream, size_t size, size_t nmemb, mem
78
82
  return size * nmemb;
79
83
  }
80
84
 
85
+ /* Used as WRITEFUNCTION for file downloads (required on Windows) */
86
+ static size_t file_write_handler(void* stream, size_t size, size_t nmemb, FILE* fp) {
87
+ fwrite(stream, size, nmemb, fp);
88
+ if (ferror(fp)) {
89
+ return 0;
90
+ } else {
91
+ /* Just always OK the write */
92
+ return size * nmemb;
93
+ }
94
+ }
95
+
81
96
  /* A non-zero return value from the progress handler will terminate the current
82
97
  * request. We use this fact in order to interrupt any request when either the
83
98
  * user calls the "interrupt" method on the session or when the Ruby interpreter
84
99
  * is attempting to exit.
85
100
  */
86
- static int session_progress_handler(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow) {
87
- struct curl_state* state = (struct curl_state*) clientp;
88
- UNUSED_ARGUMENT(dltotal);
101
+ static int session_progress_handler(void *clientp, size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) {
102
+ struct patron_curl_state* state = (struct patron_curl_state*) clientp;
89
103
  UNUSED_ARGUMENT(dlnow);
90
104
  UNUSED_ARGUMENT(ultotal);
91
105
  UNUSED_ARGUMENT(ulnow);
106
+
107
+ // Set the interrupt if the download byte limit has been reached
108
+ if(state->download_byte_limit != 0 && (dltotal > state->download_byte_limit)) {
109
+ state->interrupt = INTERRUPT_DOWNLOAD_OVERFLOW;
110
+ }
111
+
112
+ // If the interrupt value is anything except 0, the perform() call
113
+ // will be aborted by libCURL.
114
+ // Note however that some older versions of libcurl have a bug which
115
+ // makes the return value of this callback be ignored, and the request
116
+ // will actually proceed undeterred.
117
+ // See https://sourceforge.net/p/curl/bugs/1318/
92
118
  return state->interrupt;
93
119
  }
94
120
 
@@ -96,32 +122,32 @@ static int session_progress_handler(void *clientp, double dltotal, double dlnow,
96
122
  /*----------------------------------------------------------------------------*/
97
123
  /* List of active curl sessions */
98
124
 
99
- struct curl_state_list {
100
- struct curl_state *state;
101
- struct curl_state_list *next;
125
+ struct patron_curl_state_list {
126
+ struct patron_curl_state *state;
127
+ struct patron_curl_state_list *next;
102
128
  };
103
129
 
104
130
  #define CS_LIST_COMPARATOR(p, _state_) (p->state - _state_)
105
131
 
106
- static struct curl_state_list *cs_list = NULL;
132
+ static struct patron_curl_state_list *cs_list = NULL;
107
133
 
108
- static void cs_list_append( struct curl_state *state ) {
109
- struct curl_state_list *item = NULL;
134
+ static void cs_list_append( struct patron_curl_state *state ) {
135
+ struct patron_curl_state_list *item = NULL;
110
136
 
111
137
  assert(state != NULL);
112
- item = ruby_xmalloc(sizeof(struct curl_state_list));
138
+ item = ruby_xmalloc(sizeof(struct patron_curl_state_list));
113
139
  item->state = state;
114
140
  item->next = NULL;
115
141
 
116
- SGLIB_LIST_ADD(struct curl_state_list, cs_list, item, next);
142
+ SGLIB_LIST_ADD(struct patron_curl_state_list, cs_list, item, next);
117
143
  }
118
144
 
119
- static void cs_list_remove(struct curl_state *state) {
120
- struct curl_state_list *item = NULL;
145
+ static void cs_list_remove(struct patron_curl_state *state) {
146
+ struct patron_curl_state_list *item = NULL;
121
147
 
122
148
  assert(state != NULL);
123
149
 
124
- SGLIB_LIST_DELETE_IF_MEMBER(struct curl_state_list, cs_list, state, CS_LIST_COMPARATOR, next, item);
150
+ SGLIB_LIST_DELETE_IF_MEMBER(struct patron_curl_state_list, cs_list, state, CS_LIST_COMPARATOR, next, item);
125
151
  if (item) {
126
152
  ruby_xfree(item);
127
153
  }
@@ -130,8 +156,8 @@ static void cs_list_remove(struct curl_state *state) {
130
156
  static void cs_list_interrupt(VALUE data) {
131
157
  UNUSED_ARGUMENT(data);
132
158
 
133
- SGLIB_LIST_MAP_ON_ELEMENTS(struct curl_state_list, cs_list, item, next, {
134
- item->state->interrupt = 1;
159
+ SGLIB_LIST_MAP_ON_ELEMENTS(struct patron_curl_state_list, cs_list, item, next, {
160
+ item->state->interrupt = INTERRUPT_ABORT;
135
161
  });
136
162
  }
137
163
 
@@ -139,7 +165,7 @@ static void cs_list_interrupt(VALUE data) {
139
165
  /*----------------------------------------------------------------------------*/
140
166
  /* Object allocation */
141
167
 
142
- static void session_close_debug_file(struct curl_state *curl) {
168
+ static void session_close_debug_file(struct patron_curl_state *curl) {
143
169
  if (curl->debug_file && stderr != curl->debug_file) {
144
170
  fclose(curl->debug_file);
145
171
  }
@@ -147,7 +173,7 @@ static void session_close_debug_file(struct curl_state *curl) {
147
173
  }
148
174
 
149
175
  /* Cleans up the Curl handle when the Session object is garbage collected. */
150
- void session_free(struct curl_state *curl) {
176
+ void session_free(struct patron_curl_state *curl) {
151
177
  if (curl->handle) {
152
178
  curl_easy_cleanup(curl->handle);
153
179
  curl->handle = NULL;
@@ -163,10 +189,10 @@ void session_free(struct curl_state *curl) {
163
189
  free(curl);
164
190
  }
165
191
 
166
- /* Allocates curl_state data needed for a new Session object. */
192
+ /* Allocates patron_curl_state data needed for a new Session object. */
167
193
  VALUE session_alloc(VALUE klass) {
168
- struct curl_state* curl;
169
- VALUE obj = Data_Make_Struct(klass, struct curl_state, NULL, session_free, curl);
194
+ struct patron_curl_state* curl;
195
+ VALUE obj = Data_Make_Struct(klass, struct patron_curl_state, NULL, session_free, curl);
170
196
 
171
197
  membuffer_init( &curl->header_buffer );
172
198
  membuffer_init( &curl->body_buffer );
@@ -175,16 +201,22 @@ VALUE session_alloc(VALUE klass) {
175
201
  return obj;
176
202
  }
177
203
 
178
- /* Return the curl_state from the ruby VALUE which is the Session instance. */
179
- static struct curl_state* get_curl_state(VALUE self) {
180
- struct curl_state *state;
181
- Data_Get_Struct(self, struct curl_state, state);
204
+ /* Return the patron_curl_state from the ruby VALUE which is the Session instance. */
205
+ static struct patron_curl_state* get_patron_curl_state(VALUE self) {
206
+ struct patron_curl_state* state;
207
+ Data_Get_Struct(self, struct patron_curl_state, state);
182
208
 
183
209
  if (NULL == state->handle) {
184
210
  state->handle = curl_easy_init();
185
211
  curl_easy_setopt(state->handle, CURLOPT_NOSIGNAL, 1);
186
212
  curl_easy_setopt(state->handle, CURLOPT_NOPROGRESS, 0);
187
- curl_easy_setopt(state->handle, CURLOPT_PROGRESSFUNCTION, &session_progress_handler);
213
+ #if LIBCURL_VERSION_NUM >= 0x072000
214
+ /* this is libCURLv7.32.0 or later, supports CURLOPT_XFERINFOFUNCTION */
215
+ curl_easy_setopt(state->handle, CURLOPT_XFERINFOFUNCTION, &session_progress_handler);
216
+ #else
217
+ curl_easy_setopt(state->handle, CURLOPT_PROGRESSFUNCTION, &session_progress_handler);
218
+ #endif
219
+
188
220
  curl_easy_setopt(state->handle, CURLOPT_PROGRESSDATA, state);
189
221
  }
190
222
 
@@ -206,6 +238,20 @@ static VALUE libcurl_version(VALUE klass) {
206
238
  return rb_str_new2(value);
207
239
  }
208
240
 
241
+ /*
242
+ * Returns the version of the embedded libcurl.
243
+ *
244
+ * @return [Array] an array of MAJOR, MINOR, PATCH integers
245
+ */
246
+ static VALUE libcurl_version_exact(VALUE klass) {
247
+ UNUSED_ARGUMENT(klass);
248
+ VALUE cv_major = INT2FIX(LIBCURL_VERSION_MAJOR);
249
+ VALUE cv_minor = INT2FIX(LIBCURL_VERSION_MINOR);
250
+ VALUE cv_patch = INT2FIX(LIBCURL_VERSION_PATCH);
251
+ VALUE version_arr = rb_ary_new3(3, cv_major, cv_minor, cv_patch);
252
+ return version_arr;
253
+ }
254
+
209
255
  /*
210
256
  * Escapes the provided string using libCURL URL escaping functions.
211
257
  *
@@ -218,7 +264,7 @@ static VALUE session_escape(VALUE self, VALUE value) {
218
264
  char* escaped = NULL;
219
265
  VALUE retval = Qnil;
220
266
 
221
- struct curl_state* state = curl_easy_init();
267
+ struct patron_curl_state* state = curl_easy_init();
222
268
  escaped = curl_easy_escape(state->handle,
223
269
  RSTRING_PTR(string),
224
270
  (int) RSTRING_LEN(string));
@@ -241,7 +287,7 @@ static VALUE session_unescape(VALUE self, VALUE value) {
241
287
  char* unescaped = NULL;
242
288
  VALUE retval = Qnil;
243
289
 
244
- struct curl_state* state = curl_easy_init();
290
+ struct patron_curl_state* state = curl_easy_init();
245
291
  unescaped = curl_easy_unescape(state->handle,
246
292
  RSTRING_PTR(string),
247
293
  (int) RSTRING_LEN(string),
@@ -256,7 +302,7 @@ static VALUE session_unescape(VALUE self, VALUE value) {
256
302
 
257
303
  /* Callback used to iterate over the HTTP headers and store them in an slist. */
258
304
  static int each_http_header(VALUE header_key, VALUE header_value, VALUE self) {
259
- struct curl_state *state = get_curl_state(self);
305
+ struct patron_curl_state *state = get_patron_curl_state(self);
260
306
  CURL* curl = state->handle;
261
307
 
262
308
  VALUE name = rb_obj_as_string(header_key);
@@ -286,7 +332,7 @@ static int each_http_header(VALUE header_key, VALUE header_value, VALUE self) {
286
332
  }
287
333
 
288
334
  static int formadd_values(VALUE data_key, VALUE data_value, VALUE self) {
289
- struct curl_state *state = get_curl_state(self);
335
+ struct patron_curl_state *state = get_patron_curl_state(self);
290
336
  VALUE name = rb_obj_as_string(data_key);
291
337
  VALUE value = rb_obj_as_string(data_value);
292
338
 
@@ -297,7 +343,7 @@ static int formadd_values(VALUE data_key, VALUE data_value, VALUE self) {
297
343
  }
298
344
 
299
345
  static int formadd_files(VALUE data_key, VALUE data_value, VALUE self) {
300
- struct curl_state *state = get_curl_state(self);
346
+ struct patron_curl_state *state = get_patron_curl_state(self);
301
347
  VALUE name = rb_obj_as_string(data_key);
302
348
  VALUE value = rb_obj_as_string(data_value);
303
349
 
@@ -317,7 +363,7 @@ static void set_curl_request_body(CURL* curl, char* buf, curl_off_t len) {
317
363
  #endif
318
364
  }
319
365
 
320
- static void set_chunked_encoding(struct curl_state *state) {
366
+ static void set_chunked_encoding(struct patron_curl_state *state) {
321
367
  state->headers = curl_slist_append(state->headers, "Transfer-Encoding: chunked");
322
368
  }
323
369
 
@@ -330,7 +376,7 @@ static FILE* open_file(VALUE filename, const char* perms) {
330
376
  return handle;
331
377
  }
332
378
 
333
- static void set_request_body_file(struct curl_state* state, VALUE r_path_str) {
379
+ static void set_request_body_file(struct patron_curl_state* state, VALUE r_path_str) {
334
380
  CURL* curl = state->handle;
335
381
 
336
382
  state->request_body_file = open_file(r_path_str, "rb");
@@ -345,7 +391,7 @@ static void set_request_body_file(struct curl_state* state, VALUE r_path_str) {
345
391
  #endif
346
392
  }
347
393
 
348
- static void set_request_body(struct curl_state* state, VALUE stringable_or_file) {
394
+ static void set_request_body(struct patron_curl_state* state, VALUE stringable_or_file) {
349
395
  CURL* curl = state->handle;
350
396
  if(rb_respond_to(stringable_or_file, rb_intern("to_path"))) {
351
397
  // Set up a file read callback (read the entire request body from a file).
@@ -368,7 +414,7 @@ static void set_request_body(struct curl_state* state, VALUE stringable_or_file)
368
414
  * handle.
369
415
  */
370
416
  static void set_options_from_request(VALUE self, VALUE request) {
371
- struct curl_state* state = get_curl_state(self);
417
+ struct patron_curl_state* state = get_patron_curl_state(self);
372
418
  CURL* curl = state->handle;
373
419
 
374
420
  ID action = Qnil;
@@ -383,16 +429,23 @@ static void set_options_from_request(VALUE self, VALUE request) {
383
429
  VALUE insecure = Qnil;
384
430
  VALUE cacert = Qnil;
385
431
  VALUE ssl_version = Qnil;
432
+ VALUE http_version = Qnil;
386
433
  VALUE buffer_size = Qnil;
387
434
  VALUE action_name = rb_funcall(request, rb_intern("action"), 0);
388
435
  VALUE a_c_encoding = rb_funcall(request, rb_intern("automatic_content_encoding"), 0);
436
+ VALUE download_byte_limit = rb_funcall(request, rb_intern("download_byte_limit"), 0);
437
+
438
+ if (RTEST(download_byte_limit)) {
439
+ state->download_byte_limit = FIX2INT(download_byte_limit);
440
+ } else {
441
+ state->download_byte_limit = 0;
442
+ }
389
443
 
390
444
  headers = rb_funcall(request, rb_intern("headers"), 0);
391
445
  if (RTEST(headers)) {
392
446
  if (rb_type(headers) != T_HASH) {
393
447
  rb_raise(rb_eArgError, "Headers must be passed in a hash.");
394
448
  }
395
-
396
449
  rb_hash_foreach(headers, each_http_header, self);
397
450
  }
398
451
 
@@ -410,8 +463,12 @@ static void set_options_from_request(VALUE self, VALUE request) {
410
463
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
411
464
  }
412
465
  if (RTEST(download_file)) {
466
+ // we need the WRITEDATA option for the file destination
413
467
  state->download_file = open_file(download_file, "wb");
414
468
  curl_easy_setopt(curl, CURLOPT_WRITEDATA, state->download_file);
469
+ // curl docs say that CURLOPT_WRITEFUNCTION must be set too
470
+ // to avoid issues on Windows
471
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &file_write_handler);
415
472
  } else {
416
473
  state->download_file = NULL;
417
474
  }
@@ -553,17 +610,69 @@ static void set_options_from_request(VALUE self, VALUE request) {
553
610
  if(RTEST(ssl_version)) {
554
611
  VALUE ssl_version_str = rb_funcall(ssl_version, rb_intern("to_s"), 0);
555
612
  char* version = StringValuePtr(ssl_version_str);
613
+
556
614
  if(strcmp(version, "SSLv2") == 0) {
557
615
  curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv2);
558
616
  } else if(strcmp(version, "SSLv3") == 0) {
559
617
  curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);
560
618
  } else if(strcmp(version, "TLSv1") == 0) {
561
- curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
562
- } else {
619
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
620
+ }
621
+ #if LIBCURL_VERSION_NUM >= 0x072200
622
+ /* this is libCURLv7.34.0 or later */
623
+ else if(strcmp(version, "TLSv1_0") == 0) {
624
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_0); //libcurl v7.34.0+
625
+ } else if(strcmp(version, "TLSv1_1") == 0) {
626
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1); //libcurl v7.34.0+
627
+ } else if(strcmp(version, "TLSv1_2") == 0) {
628
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); //libcurl v7.34.0+
629
+ }
630
+ #endif
631
+ #if LIBCURL_VERSION_NUM >= 0x073400
632
+ /* this is libCURLv7.52.0 or later */
633
+ else if(strcmp(version, "TLSv1_3") == 0) {
634
+ curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_3); //libcurl v7.52.0+
635
+ }
636
+ #endif
637
+ else {
563
638
  rb_raise(eUnsupportedSSLVersion, "Unsupported SSL version: %s", version);
564
639
  }
565
640
  }
566
641
 
642
+ http_version = rb_funcall(request, rb_intern("http_version"), 0);
643
+ if(RTEST(http_version)) {
644
+ VALUE http_version_str = rb_funcall(http_version, rb_intern("to_s"), 0);
645
+ char* version = StringValuePtr(http_version_str);
646
+ if(strcmp(version, "None") == 0) {
647
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_NONE);
648
+ } else if(strcmp(version, "HTTPv1_0") == 0) {
649
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
650
+ } else if(strcmp(version, "HTTPv1_1") == 0) {
651
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
652
+ }
653
+ #if LIBCURL_VERSION_NUM >= 0x072100
654
+ /* this is libCURLv7.33.0 or later */
655
+ else if(strcmp(version, "HTTPv2_0") == 0) {
656
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0); //libcurl v7.33.0+
657
+ }
658
+ #endif
659
+ #if LIBCURL_VERSION_NUM >= 0x072F00
660
+ /* this is libCURLv7.47.0 or later */
661
+ else if(strcmp(version, "HTTPv2_TLS") == 0) {
662
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS); //libcurl v7.47.0+
663
+ }
664
+ #endif
665
+ #if LIBCURL_VERSION_NUM >= 0x073100
666
+ /* this is libCURLv7.49.0 or later */
667
+ else if(strcmp(version, "HTTPv2_PRIOR") == 0) {
668
+ curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE); //libcurl v7.49.0+
669
+ }
670
+ #endif
671
+ else {
672
+ rb_raise(eUnsupportedHTTPVersion, "Unsupported HTTP version: %s", version);
673
+ }
674
+ }
675
+
567
676
  cacert = rb_funcall(request, rb_intern("cacert"), 0);
568
677
  if(RTEST(cacert)) {
569
678
  curl_easy_setopt(curl, CURLOPT_CAINFO, StringValuePtr(cacert));
@@ -616,7 +725,7 @@ static VALUE select_error(CURLcode code) {
616
725
  case CURLE_PARTIAL_FILE: error = ePartialFileError; break;
617
726
  case CURLE_OPERATION_TIMEDOUT: error = eTimeoutError; break;
618
727
  case CURLE_TOO_MANY_REDIRECTS: error = eTooManyRedirects; break;
619
-
728
+ case CURLE_ABORTED_BY_CALLBACK: error = eAborted; break;
620
729
  default: error = ePatronError;
621
730
  }
622
731
 
@@ -625,13 +734,13 @@ static VALUE select_error(CURLcode code) {
625
734
 
626
735
  /* Perform the actual HTTP request by calling libcurl. */
627
736
  static VALUE perform_request(VALUE self) {
628
- struct curl_state *state = get_curl_state(self);
737
+ struct patron_curl_state *state = get_patron_curl_state(self);
629
738
  CURL* curl = state->handle;
630
739
  membuffer* header_buffer = NULL;
631
740
  membuffer* body_buffer = NULL;
632
741
  CURLcode ret = 0;
633
742
 
634
- state->interrupt = 0; /* clear any interrupt flags */
743
+ state->interrupt = 0; /* clear the interrupt flag */
635
744
 
636
745
  header_buffer = &state->header_buffer;
637
746
  body_buffer = &state->body_buffer;
@@ -682,7 +791,7 @@ static VALUE perform_request(VALUE self) {
682
791
  * all request related objects such as the header slist.
683
792
  */
684
793
  static VALUE cleanup(VALUE self) {
685
- struct curl_state *state = get_curl_state(self);
794
+ struct patron_curl_state *state = get_patron_curl_state(self);
686
795
  curl_easy_reset(state->handle);
687
796
 
688
797
  if (state->headers) {
@@ -741,8 +850,8 @@ static VALUE session_handle_request(VALUE self, VALUE request) {
741
850
  * @return self
742
851
  */
743
852
  static VALUE session_reset(VALUE self) {
744
- struct curl_state *state;
745
- Data_Get_Struct(self, struct curl_state, state);
853
+ struct patron_curl_state *state;
854
+ Data_Get_Struct(self, struct patron_curl_state, state);
746
855
 
747
856
  if (NULL != state->handle) {
748
857
  cleanup(self);
@@ -760,8 +869,8 @@ static VALUE session_reset(VALUE self) {
760
869
  * @return [void] This method always raises
761
870
  */
762
871
  static VALUE session_interrupt(VALUE self) {
763
- struct curl_state *state = get_curl_state(self);
764
- state->interrupt = 1;
872
+ struct patron_curl_state *state = get_patron_curl_state(self);
873
+ state->interrupt = INTERRUPT_ABORT;
765
874
  return self;
766
875
  }
767
876
 
@@ -775,7 +884,7 @@ static VALUE session_interrupt(VALUE self) {
775
884
  * @return self
776
885
  */
777
886
  static VALUE add_cookie_file(VALUE self, VALUE file) {
778
- struct curl_state *state = get_curl_state(self);
887
+ struct patron_curl_state *state = get_patron_curl_state(self);
779
888
  CURL* curl = state->handle;
780
889
  char* file_path = NULL;
781
890
 
@@ -796,7 +905,7 @@ static VALUE add_cookie_file(VALUE self, VALUE file) {
796
905
  * @return self
797
906
  */
798
907
  static VALUE set_debug_file(VALUE self, VALUE file) {
799
- struct curl_state *state = get_curl_state(self);
908
+ struct patron_curl_state *state = get_patron_curl_state(self);
800
909
  char* file_path = RSTRING_PTR(file);
801
910
 
802
911
  session_close_debug_file(state);
@@ -826,14 +935,17 @@ void Init_session_ext() {
826
935
 
827
936
  eUnsupportedProtocol = rb_const_get(mPatron, rb_intern("UnsupportedProtocol"));
828
937
  eUnsupportedSSLVersion = rb_const_get(mPatron, rb_intern("UnsupportedSSLVersion"));
938
+ eUnsupportedHTTPVersion = rb_const_get(mPatron, rb_intern("UnsupportedHTTPVersion"));
829
939
  eURLFormatError = rb_const_get(mPatron, rb_intern("URLFormatError"));
830
940
  eHostResolutionError = rb_const_get(mPatron, rb_intern("HostResolutionError"));
831
941
  eConnectionFailed = rb_const_get(mPatron, rb_intern("ConnectionFailed"));
832
942
  ePartialFileError = rb_const_get(mPatron, rb_intern("PartialFileError"));
833
943
  eTimeoutError = rb_const_get(mPatron, rb_intern("TimeoutError"));
834
944
  eTooManyRedirects = rb_const_get(mPatron, rb_intern("TooManyRedirects"));
945
+ eAborted = rb_const_get(mPatron, rb_intern("Aborted"));
835
946
 
836
- rb_define_module_function(mPatron, "libcurl_version", libcurl_version, 0);
947
+ rb_define_module_function(mPatron, "libcurl_version", libcurl_version, 0);
948
+ rb_define_module_function(mPatron, "libcurl_version_exact", libcurl_version_exact, 0);
837
949
 
838
950
  cSession = rb_define_class_under(mPatron, "Session", rb_cObject);
839
951
  cRequest = rb_define_class_under(mPatron, "Request", rb_cObject);
data/lib/patron/error.rb CHANGED
@@ -36,6 +36,9 @@ module Patron
36
36
  # Gets raised when a request is attempted with an unsupported SSL version.
37
37
  class UnsupportedSSLVersion < Error; end
38
38
 
39
+ # Gets raised when a request is attempted with an unsupported HTTP version.
40
+ class UnsupportedHTTPVersion < Error; end
41
+
39
42
  # Gets raised when the URL was not properly formatted.
40
43
  class URLFormatError < Error; end
41
44
 
@@ -56,6 +59,9 @@ module Patron
56
59
  # Gets raised on too many redirects. When following redirects, Patron hit the maximum amount.
57
60
  class TooManyRedirects < Error; end
58
61
 
62
+ # Gets raised if the progress callback, or an interrupt, aborts the Curl perform() call
63
+ class Aborted < Error; end
64
+
59
65
  # Gets raised when the server specifies an encoding that could not be found, or has an invalid name,
60
66
  # or when the server "lies" about the encoding of the response body (such as can be the case
61
67
  # when the server specifies an encoding in `Content-Type`) which the HTML generator then overrides
@@ -50,12 +50,12 @@ module Patron
50
50
  :url, :username, :password, :file_name, :proxy, :proxy_type, :insecure,
51
51
  :ignore_content_length, :multipart, :action, :timeout, :connect_timeout,
52
52
  :max_redirects, :headers, :auth_type, :upload_data, :buffer_size, :cacert,
53
- :ssl_version, :automatic_content_encoding, :force_ipv4
53
+ :ssl_version, :http_version, :automatic_content_encoding, :force_ipv4, :download_byte_limit
54
54
  ]
55
55
 
56
56
  WRITER_VARS = [
57
57
  :url, :username, :password, :file_name, :proxy, :proxy_type, :insecure,
58
- :ignore_content_length, :multipart, :cacert, :ssl_version, :automatic_content_encoding, :force_ipv4
58
+ :ignore_content_length, :multipart, :cacert, :ssl_version, :http_version, :automatic_content_encoding, :force_ipv4, :download_byte_limit
59
59
  ]
60
60
 
61
61
  attr_reader *READER_VARS
@@ -33,13 +33,13 @@ module Patron
33
33
  # @return [String] the original URL used to perform the request (contains the final URL after redirects)
34
34
  attr_reader :url
35
35
 
36
- # @return [Fixnum] the HTTP status code of the final response after all the redirects
36
+ # @return [Integer] the HTTP status code of the final response after all the redirects
37
37
  attr_reader :status
38
38
 
39
39
  # @return [String] the complete status line (code and message)
40
40
  attr_reader :status_line
41
41
 
42
- # @return [Fixnum] how many redirects were followed when fulfilling this request
42
+ # @return [Integer] how many redirects were followed when fulfilling this request
43
43
  attr_reader :redirect_count
44
44
 
45
45
  # @return [String, nil] the response body as a String encoded as `Encoding::BINARY` or
@@ -82,6 +82,10 @@ module Patron
82
82
  # The supported values are nil, "SSLv2", "SSLv3", and "TLSv1".
83
83
  attr_accessor :ssl_version
84
84
 
85
+ # @return [String] the HTTP version for the requests, or "None" if libcurl is to choose permitted versions
86
+ # The supported values are "None", "HTTPv1_0", "HTTPv1_1", "HTTPv2_0", "HTTPv2_TLS", and "HTTPv2_PRIOR".
87
+ attr_accessor :http_version
88
+
85
89
  # @return [String] path to the CA file used for certificate verification, or `nil` if CURL default is used
86
90
  attr_accessor :cacert
87
91
 
@@ -105,7 +109,12 @@ module Patron
105
109
 
106
110
  # @return [Boolean] Support automatic Content-Encoding decompression and set liberal Accept-Encoding headers
107
111
  attr_accessor :automatic_content_encoding
108
-
112
+
113
+ # @return [Fixnum, nil] Limit the amount of bytes downloaded. If it is set to nil
114
+ # (default) no limit will be applied.
115
+ # **Note that this only works on libCURL 7.34 and newer**
116
+ attr_accessor :download_byte_limit
117
+
109
118
  private :handle_request, :add_cookie_file, :set_debug_file
110
119
 
111
120
  # Create a new Session object for performing requests.
@@ -371,9 +380,11 @@ module Patron
371
380
  req.auth_type = options.fetch :auth_type, self.auth_type
372
381
  req.insecure = options.fetch :insecure, self.insecure
373
382
  req.ssl_version = options.fetch :ssl_version, self.ssl_version
383
+ req.http_version = options.fetch :http_version, self.http_version
374
384
  req.cacert = options.fetch :cacert, self.cacert
375
385
  req.ignore_content_length = options.fetch :ignore_content_length, self.ignore_content_length
376
386
  req.buffer_size = options.fetch :buffer_size, self.buffer_size
387
+ req.download_byte_limit = options.fetch :download_byte_limit, self.download_byte_limit
377
388
  req.multipart = options[:multipart]
378
389
  req.upload_data = options[:data]
379
390
  req.file_name = options[:file]
@@ -1,3 +1,3 @@
1
1
  module Patron
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.1"
3
3
  end
data/patron.gemspec CHANGED
@@ -1,33 +1,44 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require File.expand_path("../lib/patron/version", __FILE__)
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'patron/version'
3
5
 
4
- Gem::Specification.new do |s|
5
- s.name = "patron"
6
- s.version = Patron::VERSION
7
- s.platform = Gem::Platform::RUBY
8
- s.authors = ["Phillip Toland"]
9
- s.email = ["phil.toland@gmail.com"]
10
- s.homepage = "https://github.com/toland/patron"
11
- s.summary = "Patron HTTP Client"
12
- s.description = "Ruby HTTP client library based on libcurl"
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "patron"
8
+ spec.version = Patron::VERSION
9
+ spec.platform = Gem::Platform::RUBY
10
+ spec.authors = ["Phillip Toland"]
11
+ spec.email = ["phil.toland@gmail.com"]
12
+ spec.homepage = "https://github.com/toland/patron"
13
+ spec.summary = "Patron HTTP Client"
14
+ spec.description = "Ruby HTTP client library based on libcurl"
13
15
 
14
- s.required_rubygems_version = ">= 1.2.0"
15
- s.rubyforge_project = "patron"
16
+ # Prevent pushing this gem to RubyGemspec.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushespec."
22
+ end
23
+
24
+ spec.required_rubygems_version = ">= 1.2.0"
25
+ spec.rubyforge_project = "patron"
16
26
 
17
- s.add_development_dependency "bundler", ">= 1.0.0"
18
- s.add_development_dependency "rake-compiler", ">= 0.7.5"
19
- s.add_development_dependency "rspec", ">= 2.3.0"
20
- s.add_development_dependency "simplecov", ">= 0.10.0"
21
- s.add_development_dependency "yard", "~> 0.8"
22
-
23
- s.files = `git ls-files`.split("\n")
24
- s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
25
- s.require_paths = ["lib", "ext"]
26
- s.extensions = ["ext/patron/extconf.rb"]
27
- s.post_install_message = %q{
27
+ spec.files = `git ls-files -z`.split("\x0")
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib", "ext"]
31
+ spec.extensions = ["ext/patron/extconf.rb"]
32
+ spec.post_install_message = %q{
28
33
  Thank you for installing Patron. On OSX, make sure you are using libCURL with OpenSSL.
29
- SecureTransport-based builds might cause crashes in forking environments.
34
+ SecureTransport-based builds might cause crashes in forking environment.
30
35
 
31
36
  For more info see https://github.com/curl/curl/issues/788
32
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.8"
43
+ spec.add_development_dependency "rake-compiler"
33
44
  end
data/spec/patron_spec.rb CHANGED
@@ -38,9 +38,16 @@ describe Patron do
38
38
  expect(version).to match(%r|^\d+.\d+.\d+$|)
39
39
  end
40
40
 
41
- it "should return the version number of the libcurl library" do
41
+ it "should return the version string of the libcurl library" do
42
42
  version = Patron.libcurl_version
43
43
  expect(version).to match(%r|^libcurl/\d+.\d+.\d+|)
44
44
  end
45
45
 
46
+ it "should return the version numbers of the libcurl library" do
47
+ version = Patron.libcurl_version_exact
48
+ expect(version.length).to eq(3)
49
+ expect(version[0]).to be > 0
50
+ expect(version[1]).to be >= 0
51
+ expect(version[2]).to be >= 0
52
+ end
46
53
  end
@@ -45,7 +45,7 @@ describe Patron::Response do
45
45
 
46
46
  it 'recovers the status code' do
47
47
  response = @session.get("/repetitiveheader")
48
- expect(response.status).to be_kind_of(Fixnum)
48
+ expect(response.status).to be_kind_of(Integer)
49
49
  expect(response.status).to eq(200)
50
50
  end
51
51
 
data/spec/session_spec.rb CHANGED
@@ -129,6 +129,34 @@ describe Patron::Session do
129
129
  FileUtils.rm tmpfile
130
130
  end
131
131
 
132
+ it "downloads a very large file" do
133
+ tmpfile = "/tmp/large-succeeded"
134
+ @session.get_file "/very-large", tmpfile
135
+ expect(File.size(tmpfile)).to eq(15 * 1024 * 1024)
136
+ end
137
+
138
+ it "raises an exception if the download body limit is exceeded when using direct-to-file download" do
139
+ tmpfile = "/tmp/large-aborted"
140
+ @session.download_byte_limit = 1024
141
+ @session.buffer_size = 1024
142
+ expect {
143
+ @session.get_file "/very-large", tmpfile
144
+ }.to raise_error(Patron::Error)
145
+ # On Ruby 2.x Patron::Aborted takes precedence, but
146
+ # on 1.9 it will be Patron::PartialFileError
147
+ expect(File.size(tmpfile)).to be < (1024 * 3)
148
+ end
149
+
150
+ it "raises an exception if the download body limit is exceeded when using download-to-memory" do
151
+ @session.download_byte_limit = 1024
152
+ @session.buffer_size = 1024
153
+ expect {
154
+ @session.get "/very-large"
155
+ }.to raise_error(Patron::Error)
156
+ # On Ruby 2.x Patron::Aborted takes precedence, but
157
+ # on 1.9 it will be Patron::PartialFileError
158
+ end
159
+
132
160
  it "should not send the user-agent if it has been deleted from headers" do
133
161
  @session.headers.delete 'User-Agent'
134
162
  response = @session.get("/test")
@@ -284,7 +284,7 @@ describe Patron::Session do
284
284
  end
285
285
 
286
286
  it "should work with different SSL versions" do
287
- ['SSLv3', 'TLSv1'].each do |version|
287
+ ['SSLv3','TLSv1'].each do |version|
288
288
  @session.ssl_version = version
289
289
  response = @session.get("/test")
290
290
  expect(response.status).to be == 200
@@ -299,7 +299,24 @@ describe Patron::Session do
299
299
  }.to raise_error(Patron::UnsupportedSSLVersion)
300
300
  end
301
301
  end
302
-
302
+
303
+ it "should work with different HTTP versions" do
304
+ ['HTTPv1_0','HTTPv1_1'].each do |version|
305
+ @session.http_version = version
306
+ response = @session.get("/test")
307
+ expect(response.status).to be == 200
308
+ end
309
+ end
310
+
311
+ it "should raise when an unsupported or unknown HTTP version is requested" do
312
+ ['something', 1].each do |version|
313
+ @session.http_version = version
314
+ expect {
315
+ @session.get("/test")
316
+ }.to raise_error(Patron::UnsupportedHTTPVersion)
317
+ end
318
+ end
319
+
303
320
  # ------------------------------------------------------------------------
304
321
  describe 'when debug is enabled' do
305
322
  it 'it should not clobber stderr' do
@@ -163,6 +163,14 @@ class WrongContentLengthServlet < HTTPServlet::AbstractServlet
163
163
  end
164
164
  end
165
165
 
166
+ # Serves a substantial amount of data
167
+ class LargeServlet < HTTPServlet::AbstractServlet
168
+ def do_GET(req, res)
169
+ res.content_length = 15 * 1024 * 1024
170
+ res.body = Random.new.bytes(15 * 1024 * 1024)
171
+ end
172
+ end
173
+
166
174
  class PatronTestServer
167
175
 
168
176
  def self.start( log_file = nil, ssl = false, port = 9001 )
@@ -198,6 +206,7 @@ class PatronTestServer
198
206
  @server.mount("/redirect", RedirectServlet)
199
207
  @server.mount("/evil-redirect", EvilRedirectServlet)
200
208
  @server.mount("/picture", PictureServlet)
209
+ @server.mount("/very-large", LargeServlet)
201
210
  @server.mount("/setcookie", SetCookieServlet)
202
211
  @server.mount("/repetitiveheader", RepetitiveHeaderServlet)
203
212
  @server.mount("/wrongcontentlength", WrongContentLengthServlet)
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phillip Toland
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-05 00:00:00.000000000 Z
11
+ date: 2017-07-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: bundler
14
+ name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ">="
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 1.0.0
19
+ version: '10'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ">="
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 1.0.0
26
+ version: '10'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rake-compiler
28
+ name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.7.5
33
+ version: '1'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.7.5
40
+ version: '1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -56,16 +56,16 @@ dependencies:
56
56
  name: simplecov
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ">="
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.10.0
61
+ version: '0.10'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ">="
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.10.0
68
+ version: '0.10'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: yard
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +80,20 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake-compiler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
83
97
  description: Ruby HTTP client library based on libcurl
84
98
  email:
85
99
  - phil.toland@gmail.com
@@ -130,11 +144,12 @@ files:
130
144
  - spec/util_spec.rb
131
145
  homepage: https://github.com/toland/patron
132
146
  licenses: []
133
- metadata: {}
147
+ metadata:
148
+ allowed_push_host: https://rubygems.org
134
149
  post_install_message: |2
135
150
 
136
151
  Thank you for installing Patron. On OSX, make sure you are using libCURL with OpenSSL.
137
- SecureTransport-based builds might cause crashes in forking environments.
152
+ SecureTransport-based builds might cause crashes in forking environment.
138
153
 
139
154
  For more info see https://github.com/curl/curl/issues/788
140
155
  rdoc_options: []
@@ -153,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
168
  version: 1.2.0
154
169
  requirements: []
155
170
  rubyforge_project: patron
156
- rubygems_version: 2.5.1
171
+ rubygems_version: 2.5.2
157
172
  signing_key:
158
173
  specification_version: 4
159
174
  summary: Patron HTTP Client