patron 0.8.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
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