patron 0.6.5 → 0.7.0

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: 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