patron 0.6.5 → 0.7.0

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: a7318f9bed9b99f36570d83e3c0de4fe77e9fa93
4
- data.tar.gz: 15cf5d9064bb24ce550e31e15c87feacb6d9e2a5
3
+ metadata.gz: f76646171763f7fa4dfc31e84faa095603d0a436
4
+ data.tar.gz: 1afb07a23dac44e8a082049cd5e5c4500a3ae6f8
5
5
  SHA512:
6
- metadata.gz: 07b6971951e179505a4df277951b57c5b509679fb7e1515f400fdd954e897a9b191c879ba467e409d5ef310b6fee44b7608c26cbf80d0629e1c3574be25a0487
7
- data.tar.gz: aee56e977fce8e5e629df192aa83a5a27d69dd66a767adac38adb5786e36d93186162bd6166a6292a0826e15dc4c466fc6e0e2e1c7de885fe59e40c53f3235fc
6
+ metadata.gz: e082c9ffc4a0fca0384aa00393761ca50dbbece9745b13e66c8e5776b195c2865ea03ccc79849907ab3c084a40570fff1bdd38b5e690e327a8d268e93e6058fc
7
+ data.tar.gz: eaa0104eddc56283dd2561a5aae9c4736dd5e24c433cc2a08d360900173a6ac18c1c2dd7731881a339fadf7f802a8224d22476120c01ac884746983d7bd2895f
@@ -1,3 +1,5 @@
1
+ * Allow Ruby File objects to be passed as `data` to `Session#put`, `Sesion#post` etc.
2
+
1
3
  ### 0.6.5
2
4
 
3
5
  * Prevent libCURL from doing requests to non-HTTP/HTTPS URLs, and from following redirects to such URLs
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- patron (0.6.5)
4
+ patron (0.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -26,6 +26,7 @@
26
26
  #if defined(USE_TBR) && defined(HAVE_THREAD_H)
27
27
  #include <ruby/thread.h>
28
28
  #endif
29
+ #include <sys/stat.h>
29
30
  #include <curl/curl.h>
30
31
  #include "membuffer.h"
31
32
  #include "sglib.h" /* Simple Generic Library -> http://sglib.sourceforge.net */
@@ -51,8 +52,8 @@ struct curl_state {
51
52
  CURL* handle;
52
53
  char* upload_buf;
53
54
  FILE* download_file;
54
- FILE* upload_file;
55
55
  FILE* debug_file;
56
+ FILE* request_body_file;
56
57
  char error_buf[CURL_ERROR_SIZE];
57
58
  struct curl_slist* headers;
58
59
  struct curl_httppost* post;
@@ -329,12 +330,47 @@ static FILE* open_file(VALUE filename, const char* perms) {
329
330
  return handle;
330
331
  }
331
332
 
333
+ static void set_request_body_file(struct curl_state* state, VALUE r_path_str) {
334
+ CURL* curl = state->handle;
335
+
336
+ state->request_body_file = open_file(r_path_str, "rb");
337
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
338
+ curl_easy_setopt(curl, CURLOPT_READDATA, state->request_body_file);
339
+ #ifdef CURLOPT_INFILESIZE_LARGE
340
+ struct stat stat_info;
341
+ fstat(fileno(state->request_body_file), &stat_info);
342
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, stat_info.st_size);
343
+ #else
344
+ struct stat stat_info;
345
+ fstat(fileno(state->request_body_file), &stat_info);
346
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, stat_info.st_size);
347
+ #endif
348
+ }
349
+
350
+ static void set_request_body(struct curl_state* state, VALUE stringable_or_file) {
351
+ CURL* curl = state->handle;
352
+ if(rb_respond_to(stringable_or_file, rb_intern("to_path"))) {
353
+ // Set up a file read callback (read the entire request body from a file).
354
+ // Instead of using the Ruby file reads, use #to_path to obtain the
355
+ // file path on the file system and open a file pointer to it
356
+ VALUE r_path_str = rb_funcall(stringable_or_file, rb_intern("to_path"), 0);
357
+ r_path_str = rb_funcall(r_path_str, rb_intern("to_s"), 0);
358
+ set_request_body_file(state, r_path_str);
359
+ } else {
360
+ // Set the request body from a String
361
+ VALUE data = rb_funcall(stringable_or_file, rb_intern("to_s"), 0);
362
+ long len = RSTRING_LEN(data);
363
+ state->upload_buf = StringValuePtr(data);
364
+ set_curl_request_body(curl, state->upload_buf, len);
365
+ }
366
+ }
367
+
332
368
  /* Set the options on the Curl handle from a Request object. Takes each field
333
369
  * in the Request object and uses it to set the appropriate option on the Curl
334
370
  * handle.
335
371
  */
336
372
  static void set_options_from_request(VALUE self, VALUE request) {
337
- struct curl_state *state = get_curl_state(self);
373
+ struct curl_state* state = get_curl_state(self);
338
374
  CURL* curl = state->handle;
339
375
 
340
376
  ID action = Qnil;
@@ -372,10 +408,7 @@ static void set_options_from_request(VALUE self, VALUE request) {
372
408
 
373
409
  curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
374
410
  if (RTEST(data)) {
375
- data = rb_funcall(data, rb_intern("to_s"), 0);
376
- long len = RSTRING_LEN(data);
377
- state->upload_buf = StringValuePtr(data);
378
- set_curl_request_body(curl, state->upload_buf, len);
411
+ set_request_body(state, data);
379
412
  curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
380
413
  }
381
414
  if (RTEST(download_file)) {
@@ -398,30 +431,24 @@ static void set_options_from_request(VALUE self, VALUE request) {
398
431
  }
399
432
 
400
433
  if (RTEST(data) && !RTEST(multipart)) {
401
- data = rb_funcall(data, rb_intern("to_s"), 0);
402
434
  if (action == rb_intern("post")) {
403
435
  curl_easy_setopt(curl, CURLOPT_POST, 1);
404
436
  }
405
- long len = RSTRING_LEN(data);
406
- state->upload_buf = StringValuePtr(data);
407
- set_curl_request_body(curl, state->upload_buf, len);
437
+ set_request_body(state, data);
408
438
  } else if (RTEST(filename) && !RTEST(multipart)) {
409
439
  set_chunked_encoding(state);
410
-
411
- curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
412
-
413
- state->upload_file = open_file(filename, "rb");
414
- curl_easy_setopt(curl, CURLOPT_READDATA, state->upload_file);
440
+ set_request_body_file(state, filename);
415
441
  } else if (RTEST(multipart)) {
416
442
  if (action == rb_intern("post")) {
417
443
  if(RTEST(data) && RTEST(filename)) {
418
444
  if (rb_type(data) == T_HASH && rb_type(filename) == T_HASH) {
419
445
  rb_hash_foreach(data, formadd_values, self);
420
446
  rb_hash_foreach(filename, formadd_files, self);
421
- } else { rb_raise(rb_eArgError, "Data and Filename must be passed in a hash.");}
447
+ } else {
448
+ rb_raise(rb_eArgError, "Data and Filename must be passed in a hash.");
449
+ }
422
450
  }
423
451
  curl_easy_setopt(curl, CURLOPT_HTTPPOST, state->post);
424
-
425
452
  } else {
426
453
  rb_raise(rb_eArgError, "Multipart PUT not supported");
427
454
  }
@@ -670,11 +697,11 @@ static VALUE cleanup(VALUE self) {
670
697
  state->download_file = NULL;
671
698
  }
672
699
 
673
- if (state->upload_file) {
674
- fclose(state->upload_file);
675
- state->upload_file = NULL;
700
+ if (state->request_body_file) {
701
+ fclose(state->request_body_file);
702
+ state->request_body_file = NULL;
676
703
  }
677
-
704
+
678
705
  if (state->post) {
679
706
  curl_formfree(state->post);
680
707
  state->post = NULL;
@@ -226,7 +226,9 @@ module Patron
226
226
  #
227
227
  # @todo inconsistency with "post" - Hash not accepted
228
228
  # @param url[String] the URL to fetch
229
- # @param data[#to_s] an object that can be converted to a String to create the request body
229
+ # @param data[#to_s, #to_path] an object that can be converted to a String
230
+ # to create the request body, or that responds to #to_path to upload the
231
+ # entire request body from that file
230
232
  # @param headers[Hash] the hash of header keys to values
231
233
  # @return [Patron::Response]
232
234
  def put(url, data, headers = {})
@@ -238,7 +240,9 @@ module Patron
238
240
  #
239
241
  # @todo inconsistency with "post" - Hash not accepted
240
242
  # @param url[String] the URL to fetch
241
- # @param data[#to_s] an object that can be converted to a String to create the request body
243
+ # @param data[#to_s, #to_path] an object that can be converted to a String
244
+ # to create the request body, or that responds to #to_path to upload the
245
+ # entire request body from that file
242
246
  # @param headers[Hash] the hash of header keys to values
243
247
  # @return [Patron::Response]
244
248
  def patch(url, data, headers = {})
@@ -259,7 +263,10 @@ module Patron
259
263
  # Uploads the passed `data` to the specified `url` using an HTTP POST.
260
264
  #
261
265
  # @param url[String] the URL to fetch
262
- # @param data[Hash, #to_s] a Hash of form fields/values, or an object that can be converted to a String to create the request body
266
+ # @param data[Hash, #to_s, #to_path] a Hash of form fields/values,
267
+ # or an object that can be converted to a String
268
+ # to create the request body, or an object that responds to #to_path to upload the
269
+ # entire request body from that file
263
270
  # @param headers[Hash] the hash of header keys to values
264
271
  # @return [Patron::Response]
265
272
  def post(url, data, headers = {})
@@ -293,7 +300,6 @@ module Patron
293
300
  request(:post, url, headers, {:data => data, :file => filename, :multipart => true})
294
301
  end
295
302
 
296
-
297
303
  # @!group WebDAV methods
298
304
  # Sends a WebDAV COPY request to the specified +url+.
299
305
  #
@@ -1,3 +1,3 @@
1
1
  module Patron
2
- VERSION = "0.6.5"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -248,6 +248,17 @@ describe Patron::Session do
248
248
  expect(body.header['content-length']).to be == [data.size.to_s]
249
249
  end
250
250
 
251
+ it "should upload a Tempfile with :put" do
252
+ data = Tempfile.new 'data-buffer'
253
+ data << Random.new.bytes(1024 * 64)
254
+ data.flush; data.rewind
255
+
256
+ response = @session.put("/test", data, {'Expect' => ''})
257
+ body = YAML::load(response.body)
258
+ expect(body.request_method).to be == "PUT"
259
+ expect(body.header['content-length']).to be == [data.size.to_s]
260
+ end
261
+
251
262
  it "should upload data with :patch" do
252
263
  data = "upload data"
253
264
  response = @session.patch("/testpatch", data)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: patron
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.5
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Phillip Toland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-06-07 00:00:00.000000000 Z
11
+ date: 2016-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler