patron 0.6.0 → 0.6.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: c0a3e8dc6975392e43cac53cb03387ef07c3cab3
4
- data.tar.gz: c58f5c72242c526bd2b8a9a70f13fa53248512e4
3
+ metadata.gz: 10e347aa0ab1915c0d428cbfaf4bd6888ae2a9ba
4
+ data.tar.gz: 76476a77a366bd7b5b2aacc7fe946b26e142b995
5
5
  SHA512:
6
- metadata.gz: d4e0312f0cf82ed1db7d980bd93771016e710e7d2b1c6c3b7d7eaf965ff654eba61199eaa6a54df44e9c9ece0f610a8b16eb4bde37fce15b84fb733abf61f531
7
- data.tar.gz: 28e92d83ad9d9e7e173c327c7797b6d11240e41c1fceadb4e3cfdbc9a35abe0597150c2ab32626d183992ec835d5bfd1a6c771df506e10b2fe44c9ca3ada15d1
6
+ metadata.gz: 66045fc85f95a730550b061b255cc1420c4b0e6feee1a5cf5252d5cda68dad5792a146ea290208b683d5fe05c596d767864ef6189cade817c84792b4ae963f47
7
+ data.tar.gz: c7292c8749d8c70e051b032069fe136e6715c8158c4b8b5a9b9c24967a629aa2314b77ea8e5addca9880163facebe728b255e7a3063a803b8fbc33ee100b2bc6
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ rdoc
6
6
  doc
7
7
  pkg
8
8
  tmp
9
+ .yardoc
@@ -0,0 +1,6 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.1.5
4
+ - 2.2.2
5
+ sudo: false
6
+ cache: bundler
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- patron (0.5.1)
4
+ patron (0.6.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -30,6 +30,7 @@ GEM
30
30
  json (~> 1.8)
31
31
  simplecov-html (~> 0.10.0)
32
32
  simplecov-html (0.10.0)
33
+ yard (0.8.7.6)
33
34
 
34
35
  PLATFORMS
35
36
  ruby
@@ -40,6 +41,7 @@ DEPENDENCIES
40
41
  rake-compiler (>= 0.7.5)
41
42
  rspec (>= 2.3.0)
42
43
  simplecov (>= 0.10.0)
44
+ yard (~> 0.8)
43
45
 
44
46
  BUNDLED WITH
45
47
  1.11.2
data/README.md CHANGED
@@ -1,15 +1,10 @@
1
- # Ruby HTTP Client
2
-
3
- ## SYNOPSIS
4
-
5
1
  Patron is a Ruby HTTP client library based on libcurl. It does not try to expose
6
2
  the full "power" (read complexity) of libcurl but instead tries to provide a
7
3
  sane API while taking advantage of libcurl under the hood.
8
4
 
5
+ ## Usage
9
6
 
10
- ## USAGE
11
-
12
- Usage is very simple. First, you instantiate a Session object. You can set a few
7
+ First, you instantiate a Session object. You can set a few
13
8
  default options on the Session instance that will be used by all subsequent
14
9
  requests:
15
10
 
@@ -55,18 +50,27 @@ You can ship custom headers with a single request:
55
50
 
56
51
  sess.post("/foo/stuff", "some data", {"Content-Type" => "text/plain"})
57
52
 
58
- That is pretty much all there is to it.
53
+ ## Threading
59
54
 
55
+ By itself, the `Patron::Session` objects are not thread safe (each `Session` holds a single `curl_state` pointer
56
+ during the request/response cycle). At this time, Patron has no support for `curl_multi_*` family of functions
57
+ for doing concurrent requests. However, the actual code that interacts with libCURL does unlock the RVM GIL,
58
+ so using multiple `Session` objects in different threads is possible with a high degree of concurrency.
59
+ For sharing a resource of sessions between threads we recommend using the excellent [connection_pool](https://rubygems.org/gems/connection_pool) gem by Mike Perham.
60
60
 
61
- ## REQUIREMENTS
61
+ patron_pool = ConnectionPool.new(size: 5, timeout: 5) { Patron::Session.new }
62
+ patron_pool.with do |session|
63
+ session.get(...)
64
+ end
65
+
66
+ ## Requirements
62
67
 
63
68
  You need a recent version of libcurl in order to install this gem. On MacOS X
64
69
  the provided libcurl is sufficient. You will have to install the libcurl
65
70
  development packages on Debian or Ubuntu. Other Linux systems are probably
66
71
  similar. Windows users are on your own. Good luck with that.
67
72
 
68
-
69
- ## INSTALL
73
+ ## Installation
70
74
 
71
75
  sudo gem install patron
72
76
 
data/Rakefile CHANGED
@@ -22,10 +22,10 @@
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
24
  require 'rake/clean'
25
- require 'rdoc/task'
26
25
  require 'rake/extensiontask'
27
26
  require 'rspec/core/rake_task'
28
27
  require 'bundler'
28
+ require 'yard'
29
29
 
30
30
  Rake::ExtensionTask.new do |ext|
31
31
  ext.name = 'session_ext' # indicate the name of the extension.
@@ -43,12 +43,11 @@ task :shell => :compile do
43
43
  sh 'irb -I./lib -I./ext -r patron'
44
44
  end
45
45
 
46
- Rake::RDocTask.new do |rdoc|
47
- rdoc.rdoc_dir = 'rdoc'
48
- rdoc.title = 'Patron documentation'
49
- rdoc.main = 'README.txt'
50
- rdoc.rdoc_files.include('README.txt')
51
- rdoc.rdoc_files.include('lib/**/*.rb')
46
+ desc "Generate YARD documentation"
47
+ YARD::Rake::YardocTask.new do |t|
48
+ t.files = ['lib/**/*.rb', 'ext/**/*.c' ]
49
+ t.options = ['--markup markdown']
50
+ t.stats_options = ['--list-undoc']
52
51
  end
53
52
 
54
53
  desc "Run specs"
@@ -22,6 +22,7 @@
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
24
 
25
+
25
26
  require 'mkmf'
26
27
  require 'rbconfig'
27
28
 
@@ -38,6 +38,7 @@ static VALUE cSession = Qnil;
38
38
  static VALUE cRequest = Qnil;
39
39
  static VALUE ePatronError = Qnil;
40
40
  static VALUE eUnsupportedProtocol = Qnil;
41
+ static VALUE eUnsupportedSSLVersion = Qnil;
41
42
  static VALUE eURLFormatError = Qnil;
42
43
  static VALUE eHostResolutionError = Qnil;
43
44
  static VALUE eConnectionFailed = Qnil;
@@ -206,10 +207,10 @@ static struct curl_state* get_curl_state(VALUE self) {
206
207
  /*----------------------------------------------------------------------------*/
207
208
  /* Method implementations */
208
209
 
209
- /* call-seq:
210
- * Patron.libcurl_version -> version string
211
- *
212
- * Returns the version of the embedded libcurl as a string.
210
+ /*
211
+ * Returns the version of the embedded libcurl.
212
+ *
213
+ * @return [String] libcurl version string
213
214
  */
214
215
  static VALUE libcurl_version(VALUE klass) {
215
216
  char* value = curl_version();
@@ -217,10 +218,11 @@ static VALUE libcurl_version(VALUE klass) {
217
218
  return rb_str_new2(value);
218
219
  }
219
220
 
220
- /* call-seq:
221
- * Session.escape( string ) -> escaped string
221
+ /*
222
+ * Escapes the provided string using libCURL URL escaping functions.
222
223
  *
223
- * URL escapes the provided string.
224
+ * @param [String] value plain string to URL-escape
225
+ * @return [String] the escaped string
224
226
  */
225
227
  static VALUE session_escape(VALUE self, VALUE value) {
226
228
 
@@ -240,10 +242,11 @@ static VALUE session_escape(VALUE self, VALUE value) {
240
242
  return retval;
241
243
  }
242
244
 
243
- /* call-seq:
244
- * Session.unescape( string ) -> unescaped string
245
+ /*
246
+ * Unescapes the provided string using libCURL URL escaping functions.
245
247
  *
246
- * Unescapes the provided string.
248
+ * @param [String] value URL-encoded String to unescape
249
+ * @return [String] unescaped (decoded) string
247
250
  */
248
251
  static VALUE session_unescape(VALUE self, VALUE value) {
249
252
  VALUE string = StringValue(value);
@@ -271,7 +274,8 @@ static int each_http_header(VALUE header_key, VALUE header_value, VALUE self) {
271
274
  VALUE name = rb_obj_as_string(header_key);
272
275
  VALUE value = rb_obj_as_string(header_value);
273
276
  VALUE header_str = Qnil;
274
-
277
+
278
+ // TODO: see how to combine this with automatic_content_encoding
275
279
  if (rb_str_cmp(name, rb_str_new2("Accept-Encoding")) == 0) {
276
280
  if (rb_funcall(value, rb_intern("include?"), 1, rb_str_new2("gzip"))) {
277
281
  #ifdef CURLOPT_ACCEPT_ENCODING
@@ -461,7 +465,14 @@ static void set_options_from_request(VALUE self, VALUE request) {
461
465
  // Enable automatic content-encoding support via gzip/deflate if set in the request,
462
466
  // see https://curl.haxx.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html
463
467
  if(RTEST(a_c_encoding)) {
464
- curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
468
+ #ifdef CURLOPT_ACCEPT_ENCODING
469
+ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
470
+ #elif defined CURLOPT_ENCODING
471
+ curl_easy_setopt(curl, CURLOPT_ENCODING, "");
472
+ #else
473
+ rb_raise(rb_eArgError,
474
+ "The libcurl version installed doesn't support automatic content negotiation");
475
+ #endif
465
476
  }
466
477
 
467
478
  url = rb_iv_get(request, "@url");
@@ -494,12 +505,12 @@ static void set_options_from_request(VALUE self, VALUE request) {
494
505
 
495
506
  proxy_type = rb_iv_get(request, "@proxy_type");
496
507
  if (!NIL_P(proxy_type)) {
497
- curl_easy_setopt(curl, CURLOPT_PROXYTYPE, FIX2INT(proxy_type));
508
+ curl_easy_setopt(curl, CURLOPT_PROXYTYPE, NUM2LONG(proxy_type));
498
509
  }
499
510
 
500
511
  credentials = rb_funcall(request, rb_intern("credentials"), 0);
501
512
  if (!NIL_P(credentials)) {
502
- curl_easy_setopt(curl, CURLOPT_HTTPAUTH, FIX2INT(rb_iv_get(request, "@auth_type")));
513
+ curl_easy_setopt(curl, CURLOPT_HTTPAUTH, NUM2LONG(rb_iv_get(request, "@auth_type")));
503
514
  curl_easy_setopt(curl, CURLOPT_USERPWD, StringValuePtr(credentials));
504
515
  }
505
516
 
@@ -516,13 +527,16 @@ static void set_options_from_request(VALUE self, VALUE request) {
516
527
 
517
528
  ssl_version = rb_iv_get(request, "@ssl_version");
518
529
  if(!NIL_P(ssl_version)) {
519
- char* version = StringValuePtr(ssl_version);
530
+ VALUE ssl_version_str = rb_funcall(ssl_version, rb_intern("to_s"), 0);
531
+ char* version = StringValuePtr(ssl_version_str);
520
532
  if(strcmp(version, "SSLv2") == 0) {
521
533
  curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv2);
522
534
  } else if(strcmp(version, "SSLv3") == 0) {
523
535
  curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3);
524
536
  } else if(strcmp(version, "TLSv1") == 0) {
525
537
  curl_easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
538
+ } else {
539
+ rb_raise(eUnsupportedSSLVersion, "Unsupported SSL version: %s", version);
526
540
  }
527
541
  }
528
542
 
@@ -533,7 +547,7 @@ static void set_options_from_request(VALUE self, VALUE request) {
533
547
 
534
548
  buffer_size = rb_iv_get(request, "@buffer_size");
535
549
  if (!NIL_P(buffer_size)) {
536
- curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, FIX2INT(buffer_size));
550
+ curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, NUM2LONG(buffer_size));
537
551
  }
538
552
 
539
553
  if(state->debug_file) {
@@ -631,7 +645,9 @@ static VALUE perform_request(VALUE self) {
631
645
  VALUE header_str = membuffer_to_rb_str(header_buffer);
632
646
  VALUE body_str = Qnil;
633
647
  if (!state->download_file) { body_str = membuffer_to_rb_str(body_buffer); }
634
-
648
+
649
+ curl_easy_setopt(curl, CURLOPT_COOKIELIST, "FLUSH"); // Flush cookies to the cookie jar
650
+
635
651
  return create_response(self, curl, header_str, body_str);
636
652
  } else {
637
653
  rb_raise(select_error(ret), "%s", state->error_buf);
@@ -669,9 +685,7 @@ static VALUE cleanup(VALUE self) {
669
685
  return Qnil;
670
686
  }
671
687
 
672
- /* call-seq:
673
- * session.handle_request( request ) -> response
674
- *
688
+ /*
675
689
  * Peform the actual HTTP request by calling libcurl. Each filed in the
676
690
  * +request+ object will be used to set the appropriate option on the libcurl
677
691
  * library. After the request completes, a Response object will be created and
@@ -680,17 +694,25 @@ static VALUE cleanup(VALUE self) {
680
694
  * In the event of an error in the libcurl library, a Ruby exception will be
681
695
  * created and raised. The exception will return the libcurl error code and
682
696
  * error message.
697
+ *
698
+ * @param request[Patron::Request] the request to use when filling the CURL options
699
+ * @return [Patron::Response] the result of calling `response_class` on the Session
683
700
  */
684
701
  static VALUE session_handle_request(VALUE self, VALUE request) {
685
702
  set_options_from_request(self, request);
686
703
  return rb_ensure(&perform_request, self, &cleanup, self);
687
704
  }
688
705
 
689
- /* call-seq:
690
- * session.reset -> session
691
- *
706
+ /*
707
+ * FIXME: figure out how this method should be used at all given Session is not multithreaded.
708
+ * FIXME: also: what is the difference with `interrupt()` and also relationship with `cleanup()`?
692
709
  * Reset the underlying cURL session. This effectively closes all open
693
- * connections and disables debug output.
710
+ * connections and disables debug output. There is no need to call this method
711
+ * manually after performing a request, since cleanup is performed automatically
712
+ * but the method can be used from another thread
713
+ * to abort a request currently in progress.
714
+ *
715
+ * @return self
694
716
  */
695
717
  static VALUE session_reset(VALUE self) {
696
718
  struct curl_state *state;
@@ -706,11 +728,10 @@ static VALUE session_reset(VALUE self) {
706
728
  return self;
707
729
  }
708
730
 
709
- /* call-seq:
710
- * session.interrupt -> session
711
- *
712
- * Interrupt any currently executing request. This will cause the current
731
+ /* Interrupt any currently executing request. This will cause the current
713
732
  * request to error and raise an exception.
733
+ *
734
+ * @return [void] This method always raises
714
735
  */
715
736
  static VALUE session_interrupt(VALUE self) {
716
737
  struct curl_state *state = get_curl_state(self);
@@ -718,18 +739,21 @@ static VALUE session_interrupt(VALUE self) {
718
739
  return self;
719
740
  }
720
741
 
721
- /* call-seq:
722
- * session.enable_cookie_session( file ) -> session
723
- *
742
+ /*
724
743
  * Turn on cookie handling for this session, storing them in memory by
725
- * default or in +file+ if specified. The +file+ must be readable and
744
+ * default or in +file+ if specified. The `file` must be readable and
726
745
  * writable. Calling multiple times will add more files.
746
+ * FIXME: what does the empty string actually do here?
747
+ *
748
+ * @param [String] file path to the existing cookie file, or nil to store in memory.
749
+ * @return self
727
750
  */
728
- static VALUE enable_cookie_session(VALUE self, VALUE file) {
751
+ static VALUE add_cookie_file(VALUE self, VALUE file) {
729
752
  struct curl_state *state = get_curl_state(self);
730
753
  CURL* curl = state->handle;
731
754
  char* file_path = NULL;
732
755
 
756
+ // FIXME: http://websystemsengineering.blogspot.nl/2013/03/curloptcookiefile-vs-curloptcookiejar.html
733
757
  file_path = RSTRING_PTR(file);
734
758
  if (file_path != NULL && strlen(file_path) != 0) {
735
759
  curl_easy_setopt(curl, CURLOPT_COOKIEJAR, file_path);
@@ -739,10 +763,11 @@ static VALUE enable_cookie_session(VALUE self, VALUE file) {
739
763
  return self;
740
764
  }
741
765
 
742
- /* call-seq:
743
- * session.set_debug_file( file ) -> session
744
- *
766
+ /*
745
767
  * Enable debug output to stderr or to specified +file+.
768
+ *
769
+ * @param [String, nil] file path to the debug file, or nil to write to STDERR
770
+ * @return self
746
771
  */
747
772
  static VALUE set_debug_file(VALUE self, VALUE file) {
748
773
  struct curl_state *state = get_curl_state(self);
@@ -774,6 +799,7 @@ void Init_session_ext() {
774
799
  ePatronError = rb_const_get(mPatron, rb_intern("Error"));
775
800
 
776
801
  eUnsupportedProtocol = rb_const_get(mPatron, rb_intern("UnsupportedProtocol"));
802
+ eUnsupportedSSLVersion = rb_const_get(mPatron, rb_intern("UnsupportedSSLVersion"));
777
803
  eURLFormatError = rb_const_get(mPatron, rb_intern("URLFormatError"));
778
804
  eHostResolutionError = rb_const_get(mPatron, rb_intern("HostResolutionError"));
779
805
  eConnectionFailed = rb_const_get(mPatron, rb_intern("ConnectionFailed"));
@@ -798,20 +824,20 @@ void Init_session_ext() {
798
824
  rb_define_method(cSession, "handle_request", session_handle_request, 1);
799
825
  rb_define_method(cSession, "reset", session_reset, 0);
800
826
  rb_define_method(cSession, "interrupt", session_interrupt, 0);
801
- rb_define_method(cSession, "enable_cookie_session", enable_cookie_session, 1);
827
+ rb_define_method(cSession, "add_cookie_file", add_cookie_file, 1);
802
828
  rb_define_method(cSession, "set_debug_file", set_debug_file, 1);
803
829
  rb_define_alias(cSession, "urlencode", "escape");
804
830
  rb_define_alias(cSession, "urldecode", "unescape");
805
831
 
806
- rb_define_const(cRequest, "AuthBasic", INT2FIX(CURLAUTH_BASIC));
807
- rb_define_const(cRequest, "AuthDigest", INT2FIX(CURLAUTH_DIGEST));
808
- rb_define_const(cRequest, "AuthAny", INT2FIX(CURLAUTH_ANY));
832
+ rb_define_const(cRequest, "AuthBasic", LONG2NUM(CURLAUTH_BASIC));
833
+ rb_define_const(cRequest, "AuthDigest", LONG2NUM(CURLAUTH_DIGEST));
834
+ rb_define_const(cRequest, "AuthAny", LONG2NUM(CURLAUTH_ANY));
809
835
 
810
836
  mProxyType = rb_define_module_under(mPatron, "ProxyType");
811
- rb_define_const(mProxyType, "HTTP", INT2FIX(CURLPROXY_HTTP));
812
- rb_define_const(mProxyType, "HTTP_1_0", INT2FIX(CURLPROXY_HTTP_1_0));
813
- rb_define_const(mProxyType, "SOCKS4", INT2FIX(CURLPROXY_SOCKS4));
814
- rb_define_const(mProxyType, "SOCKS5", INT2FIX(CURLPROXY_SOCKS5));
815
- rb_define_const(mProxyType, "SOCKS4A", INT2FIX(CURLPROXY_SOCKS4A));
816
- rb_define_const(mProxyType, "SOCKS5_HOSTNAME", INT2FIX(CURLPROXY_SOCKS5_HOSTNAME));
837
+ rb_define_const(mProxyType, "HTTP", LONG2NUM(CURLPROXY_HTTP));
838
+ rb_define_const(mProxyType, "HTTP_1_0", LONG2NUM(CURLPROXY_HTTP_1_0));
839
+ rb_define_const(mProxyType, "SOCKS4", LONG2NUM(CURLPROXY_SOCKS4));
840
+ rb_define_const(mProxyType, "SOCKS5", LONG2NUM(CURLPROXY_SOCKS5));
841
+ rb_define_const(mProxyType, "SOCKS4A", LONG2NUM(CURLPROXY_SOCKS4A));
842
+ rb_define_const(mProxyType, "SOCKS5_HOSTNAME", LONG2NUM(CURLPROXY_SOCKS5_HOSTNAME));
817
843
  }
@@ -22,6 +22,8 @@
22
22
  ## THE SOFTWARE.
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
+
26
+
25
27
  require 'pathname'
26
28
 
27
29
  cwd = Pathname(__FILE__).dirname
@@ -30,8 +32,9 @@ $:.unshift(cwd.to_s) unless $:.include?(cwd.to_s) || $:.include?(cwd.expand_path
30
32
  require 'patron/session'
31
33
  require 'patron/version'
32
34
 
33
- module Patron #:nodoc:
34
- # Returns the version number of the Patron library as a string
35
+ module Patron
36
+ # Returns the version number of the gem
37
+ # @return [String]
35
38
  def self.version
36
39
  VERSION
37
40
  end
@@ -23,33 +23,37 @@
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
25
 
26
+
26
27
  module Patron
27
28
 
28
29
  # Base class for Patron exceptions.
29
30
  class Error < StandardError; end
30
31
 
31
- # The URL you passed to Patron used a protocol that it does not support.
32
+ # Gets raised when the URL passed to Patron used a protocol that it does not support.
32
33
  # This most likely the result of a misspelled protocol string.
33
34
  class UnsupportedProtocol < Error; end
34
35
 
35
- # The URL was not properly formatted.
36
+ # Gets raised when a request is attempted with an unsupported SSL version.
37
+ class UnsupportedSSLVersion < Error; end
38
+
39
+ # Gets raised when the URL was not properly formatted.
36
40
  class URLFormatError < Error; end
37
41
 
38
- # Could not resolve the remote host name.
42
+ # Gets raised when the remote host name could not be resolved.
39
43
  class HostResolutionError < Error; end
40
44
 
41
- # Failed to connect to the remote host.
45
+ # Gets raised when failing to connect to the remote host.
42
46
  class ConnectionFailed < Error; end
43
47
 
44
- # A file transfer was shorter or larger than expected.
48
+ # Gets raised when the response was shorter or larger than expected.
45
49
  # This happens when the server first reports an expected transfer size,
46
50
  # and then delivers data that doesn't match the previously given size.
47
51
  class PartialFileError < Error; end
48
52
 
49
- # Operation timeout. The specified time-out period was reached.
53
+ # Gets raised on an operation timeout. The specified time-out period was reached.
50
54
  class TimeoutError < Error; end
51
55
 
52
- # Too many redirects. When following redirects, Patron hit the maximum amount.
56
+ # Gets raised on too many redirects. When following redirects, Patron hit the maximum amount.
53
57
  class TooManyRedirects < Error; end
54
58
 
55
59
  end
@@ -1,4 +1,5 @@
1
1
  module Patron
2
+ # Represents proxy types that can be used when configured requests via CURL.
2
3
  module ProxyType
3
4
  HTTP
4
5
  HTTP_1_0
@@ -23,6 +23,7 @@
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
25
 
26
+
26
27
  require 'patron/util'
27
28
 
28
29
  module Patron
@@ -32,8 +33,11 @@ module Patron
32
33
  # used in every request.
33
34
  class Request
34
35
 
36
+ # Contains the valid HTTP verbs that can be used to perform requests
35
37
  VALID_ACTIONS = %w[GET PUT POST DELETE HEAD COPY]
36
38
 
39
+ # Initializes a new Request, which defaults to the GET HTTP verb and
40
+ # has it's timeouts set to 0
37
41
  def initialize
38
42
  @action = :get
39
43
  @headers = {}
@@ -59,7 +63,7 @@ module Patron
59
63
 
60
64
  # Set the type of authentication to use for this request.
61
65
  #
62
- # @param [String, Symbol] type - The type of authentication to use for this request, can be one of
66
+ # @param [String, Symbol]type The type of authentication to use for this request, can be one of
63
67
  # :basic, :digest, or :any
64
68
  #
65
69
  # @example
@@ -79,6 +83,16 @@ module Patron
79
83
  end
80
84
  end
81
85
 
86
+ # Sets the upload data (request body) for the request. If the
87
+ # given argument is a Hash, the contents of the hash will be handled
88
+ # as form fields and will be form-encoded. The somposition of the request
89
+ # body is then going to be handled by Curl.
90
+ #
91
+ # If the given `data` is any other object, it is going to be treated as a stringable
92
+ # request body (JSON or other verbatim type) and will have it's `to_s` method called
93
+ # before sending out the request.
94
+ #
95
+ # @param data[Hash, #to_s] a Hash of form fields to values, or an object that responds to `to_s`
82
96
  def upload_data=(data)
83
97
  @upload_data = case data
84
98
  when Hash
@@ -88,6 +102,9 @@ module Patron
88
102
  end
89
103
  end
90
104
 
105
+ # Sets the HTTP verb for the request
106
+ #
107
+ # @param action[String] the name of the HTTP verb
91
108
  def action=(action)
92
109
  if !VALID_ACTIONS.include?(action.to_s.upcase)
93
110
  raise ArgumentError, "Action must be one of #{VALID_ACTIONS.join(', ')}"
@@ -95,6 +112,9 @@ module Patron
95
112
  @action = action.downcase.to_sym
96
113
  end
97
114
 
115
+ # Sets the read timeout for the CURL request, in seconds
116
+ #
117
+ # @param new_timeout[Integer] the number of seconds to wait before raising a timeout error
98
118
  def timeout=(new_timeout)
99
119
  if new_timeout && new_timeout.to_i < 1
100
120
  raise ArgumentError, "Timeout must be a positive integer greater than 0"
@@ -103,6 +123,9 @@ module Patron
103
123
  @timeout = new_timeout.to_i
104
124
  end
105
125
 
126
+ # Sets the connect timeout for the CURL request, in seconds.
127
+ #
128
+ # @param new_timeout[Integer] the number of seconds to wait before raising a timeout error
106
129
  def connect_timeout=(new_timeout)
107
130
  if new_timeout && new_timeout.to_i < 1
108
131
  raise ArgumentError, "Timeout must be a positive integer greater than 0"
@@ -111,6 +134,9 @@ module Patron
111
134
  @connect_timeout = new_timeout.to_i
112
135
  end
113
136
 
137
+ # Sets the maximum number of redirects that are going to be followed.
138
+ #
139
+ # @param new_max_redirects[Integer] The number of redirects to follow, or `-1` for unlimited redirects.
114
140
  def max_redirects=(new_max_redirects)
115
141
  if new_max_redirects.to_i < -1
116
142
  raise ArgumentError, "Max redirects must be a positive integer, 0 or -1"
@@ -119,6 +145,10 @@ module Patron
119
145
  @max_redirects = new_max_redirects.to_i
120
146
  end
121
147
 
148
+ # Sets the headers for the request. Headers muse be set with the right capitalization.
149
+ # The previously set headers will be replaced.
150
+ #
151
+ # @param new_headers[Hash] the hash of headers to set.
122
152
  def headers=(new_headers)
123
153
  if !new_headers.kind_of?(Hash)
124
154
  raise ArgumentError, "Headers must be a hash"
@@ -127,6 +157,12 @@ module Patron
127
157
  @headers = new_headers
128
158
  end
129
159
 
160
+ # Sets the receive buffer size. This is a recommendedation value, as CURL is not guaranteed to
161
+ # honor this value internally (see https://curl.haxx.se/libcurl/c/CURLOPT_BUFFERSIZE.html).
162
+ # By default, CURL uses the maximum possible buffer size, which will be the best especially
163
+ # for smaller and quickly-executing requests.
164
+ #
165
+ # @param buffer_size[Integer,nil] the desired buffer size, or `nil` for automatic buffer size
130
166
  def buffer_size=(buffer_size)
131
167
  if buffer_size != nil && buffer_size.to_i < 1
132
168
  raise ArgumentError, "Buffer size must be a positive integer greater than 0 or nil"
@@ -135,15 +171,23 @@ module Patron
135
171
  @buffer_size = buffer_size != nil ? buffer_size.to_i : nil
136
172
  end
137
173
 
174
+ # Returns the set HTTP authentication string for basic authentication.
175
+ #
176
+ # @return [String, NilClass] the authentication string or nil if no authentication is used
138
177
  def credentials
139
178
  return nil if username.nil? || password.nil?
140
179
  "#{username}:#{password}"
141
180
  end
142
181
 
182
+ # Returns the set HTTP verb
183
+ #
184
+ # @return [String] the HTTP verb
143
185
  def action_name
144
186
  @action.to_s.upcase
145
187
  end
146
188
 
189
+ # Tells whether this Request is configured the same as the other request
190
+ # @return [TrueClass, FalseClass]
147
191
  def eql?(request)
148
192
  return false unless Request === request
149
193
 
@@ -154,12 +198,17 @@ module Patron
154
198
 
155
199
  alias_method :==, :eql?
156
200
 
201
+ # Returns a Marshalable representation of the Request
202
+ # @return [Array]
157
203
  def marshal_dump
158
204
  [ @url, @username, @password, @file_name, @proxy, @proxy_type, @insecure,
159
205
  @ignore_content_length, @multipart, @action, @timeout, @connect_timeout,
160
206
  @max_redirects, @headers, @auth_type, @upload_data, @buffer_size, @cacert ]
161
207
  end
162
208
 
209
+ # Reinstates instance variables from a marshaled representation
210
+ # @param data[Array]
211
+ # @return [void]
163
212
  def marshal_load(data)
164
213
  @url, @username, @password, @file_name, @proxy, @proxy_type, @insecure,
165
214
  @ignore_content_length, @multipart, @action, @timeout, @connect_timeout,
@@ -23,10 +23,38 @@
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
25
 
26
+
26
27
  module Patron
27
28
 
28
29
  # Represents the response from the HTTP server.
29
30
  class Response
31
+ # @return [String] the original URL used to perform the request (contains the final URL after redirects)
32
+ attr_reader :url
33
+
34
+ # @return [Fixnum] the HTTP status code of the final response after all the redirects
35
+ attr_reader :status
36
+
37
+ # @return [String] the complete status line (code and message)
38
+ attr_reader :status_line
39
+
40
+ # @return [Fixnum] how many redirects were followed when fulfilling this request
41
+ attr_reader :redirect_count
42
+
43
+ # @return [String, nil] the response body, or nil if the response was written directly to a file
44
+ attr_reader :body
45
+
46
+ # @return [Hash] the response headers. If there were multiple headers received for the same value
47
+ # (like "Cookie"), the header values will be within an Array under the key for the header, in order.
48
+ attr_reader :headers
49
+
50
+ # @return [String] the recognized name of the charset for the response
51
+ attr_reader :charset
52
+
53
+ # Overridden so that the output is shorter and there is no response body printed
54
+ def inspect
55
+ # Avoid spamming the console with the header and body data
56
+ "#<Patron::Response @status_line='#{@status_line}'>"
57
+ end
30
58
 
31
59
  def initialize(url, status, redirect_count, header_data, body, default_charset = nil)
32
60
  # Don't let a response clear out the default charset, which would cause encoding to fail
@@ -48,22 +76,7 @@ module Patron
48
76
  end
49
77
  end
50
78
 
51
- attr_reader :url, :status, :status_line, :redirect_count, :body, :headers, :charset
52
-
53
- def inspect
54
- # Avoid spamming the console with the header and body data
55
- "#<Patron::Response @status_line='#{@status_line}'>"
56
- end
57
-
58
- def marshal_dump
59
- [@url, @status, @status_line, @redirect_count, @body, @headers, @charset]
60
- end
61
-
62
- def marshal_load(data)
63
- @url, @status, @status_line, @redirect_count, @body, @headers, @charset = data
64
- end
65
-
66
- private
79
+ private
67
80
 
68
81
  def determine_charset(header_data, body)
69
82
  header_data.match(charset_regex) || (body && body.match(charset_regex))
@@ -23,6 +23,7 @@
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
25
 
26
+
26
27
  require 'uri'
27
28
  require 'patron/error'
28
29
  require 'patron/request'
@@ -36,63 +37,80 @@ module Patron
36
37
  # server. This is the primary API for Patron.
37
38
  class Session
38
39
 
39
- # HTTP connection timeout in seconds. Defaults to 1 second.
40
+ # @return [Integer] HTTP connection timeout in seconds. Defaults to 1 second.
40
41
  attr_accessor :connect_timeout
41
42
 
42
- # HTTP transaction timeout in seconds. Defaults to 5 seconds.
43
+ # @return [Integer] HTTP transaction timeout in seconds. Defaults to 5 seconds.
43
44
  attr_accessor :timeout
44
45
 
45
- # Maximum number of times to follow redirects.
46
+ # Maximum number of redirects to follow
46
47
  # Set to 0 to disable and -1 to follow all redirects. Defaults to 5.
48
+ # @return [Integer]
47
49
  attr_accessor :max_redirects
48
50
 
49
- # Prepended to the URL in all requests.
51
+ # @return [String] The URL to prepend to all requests.
50
52
  attr_accessor :base_url
51
53
 
52
- # Username and password for http authentication
53
- attr_accessor :username, :password
54
+ # Username for http authentication
55
+ # @return [String,nil] the HTTP basic auth username
56
+ attr_accessor :username
57
+
58
+ # Password for http authentication
59
+ # @return [String,nil] the HTTP basic auth password
60
+ attr_accessor :password
54
61
 
55
- # Proxy URL in cURL format ('hostname:8080')
62
+ # @return [String] Proxy URL in cURL format ('hostname:8080')
56
63
  attr_accessor :proxy
57
64
 
58
- # Proxy type (default is HTTP), see constants under ProxyType for supported types.
65
+ # @return [Integer] Proxy type (default is HTTP)
66
+ # @see Patron::ProxyType
59
67
  attr_accessor :proxy_type
60
68
 
61
- # Standard set of headers that are used in all requests.
69
+ # @return [Hash] headers used in all requests.
62
70
  attr_accessor :headers
63
71
 
64
- # Set the authentication type for the request.
72
+ # @return [Symbol] the authentication type for the request (`:basic`, `:digest` or `:token`).
65
73
  # @see Patron::Request#auth_type
66
74
  attr_accessor :auth_type
67
75
 
68
- # Does this session stricly verify SSL certificates?
76
+ # @return [Boolean] `true` if SSL certificate verification is disabled.
77
+ # Please consider twice before using this option..
69
78
  attr_accessor :insecure
70
79
 
71
- # Specifies the ssl version
80
+ # @return [String] the SSL version for the requests, or nil if all versions are permitted
81
+ # The supported values are nil, "SSLv2", "SSLv3", and "TLSv1".
72
82
  attr_accessor :ssl_version
73
83
 
74
- # What cacert file should this session use to verify SSL certificates?
84
+ # @return [String] path to the CA file used for certificate verification, or `nil` if CURL default is used
75
85
  attr_accessor :cacert
76
86
 
77
- # Does this session ignore Content-Size headers?
87
+ # @return [Boolean] whether Content-Range and Content-Length headers should be ignored
78
88
  attr_accessor :ignore_content_length
79
89
 
90
+ # @return [Integer, nil]
80
91
  # Set the buffer size for this request. This option will
81
92
  # only be set if buffer_size is non-nil
82
93
  attr_accessor :buffer_size
83
94
 
84
- # Default encoding of responses. Used if no charset is provided by the host.
95
+ # @return [String, nil]
96
+ # Sets the name of the charset to assume for the response. The argument should be a String that
97
+ # is an acceptable argument for `Encoding.find()` in Ruby. The variable will only be used if the
98
+ # response does not specify a charset in it's `Content-Type` header already, if it does that charset
99
+ # will take precedence.
85
100
  attr_accessor :default_response_charset
86
101
 
87
- # Force curl to use IPv4
102
+ # @return [Boolean] Force curl to use IPv4
88
103
  attr_accessor :force_ipv4
89
104
 
90
- # Support automatic Content-Encoding decompression and set liberal Accept-Encoding headers
105
+ # @return [Boolean] Support automatic Content-Encoding decompression and set liberal Accept-Encoding headers
91
106
  attr_accessor :automatic_content_encoding
92
107
 
93
- private :handle_request, :enable_cookie_session, :set_debug_file
108
+ private :handle_request, :add_cookie_file, :set_debug_file
94
109
 
95
110
  # Create a new Session object.
111
+ #
112
+ # @param args[Hash] options for the Session (same names as the writable attributes of the Session)
113
+ # @yield self
96
114
  def initialize(args = {}, &block)
97
115
 
98
116
  # Allows accessors to be set via constructor hash. Ex: {:base_url => 'www.home.com'}
@@ -114,73 +132,123 @@ module Patron
114
132
  end
115
133
 
116
134
  # Turn on cookie handling for this session, storing them in memory by
117
- # default or in +file+ if specified. The +file+ must be readable and
135
+ # default or in +file+ if specified. The `file` must be readable and
118
136
  # writable. Calling multiple times will add more files.
119
- def handle_cookies(file = nil)
120
- if file
121
- path = Pathname(file).expand_path
122
- unless File.exists?(file) and File.writable?(path.dirname)
137
+ #
138
+ # @todo the cookie jar and cookie file path options should be split
139
+ # @param file_path[String] path to an existing cookie jar file, or nil to store cookies in memory
140
+ # @return self
141
+ def handle_cookies(file_path = nil)
142
+ if file_path
143
+ path = Pathname(file_path).expand_path
144
+
145
+ if !File.exists?(file_path) && !File.writable?(path.dirname)
123
146
  raise ArgumentError, "Can't create file #{path} (permission error)"
124
- end
125
- unless File.readable?(file) or File.writable?(path)
147
+ elsif File.exists?(file_path) && !File.writable?(file_path)
126
148
  raise ArgumentError, "Can't read or write file #{path} (permission error)"
127
149
  end
150
+ else
151
+ path = nil
128
152
  end
129
- enable_cookie_session(path.to_s)
153
+
154
+ # Apparently calling this with an empty string sets the cookie file,
155
+ # but calling it with a path to a writable file sets that file to be
156
+ # the cookie jar (new cookies are written there)
157
+ add_cookie_file(path.to_s)
158
+
130
159
  self
131
160
  end
132
161
 
133
- # Enable debug output to stderr or to specified +file+.
162
+ # Enable debug output to stderr or to specified `file`.
163
+ #
164
+ # @todo Change to an assignment of an IO object
165
+ # @param file[String, nil] path to the file to write debug data to, or `nil` to print to `STDERR`
166
+ # @return self
134
167
  def enable_debug(file = nil)
135
168
  set_debug_file(file.to_s)
169
+ self
136
170
  end
137
171
 
138
- ###################################################################
139
- ### Standard HTTP methods
140
- ###
141
-
142
- # Retrieve the contents of the specified +url+ optionally sending the
172
+ # Retrieve the contents of the specified `url` optionally sending the
143
173
  # specified headers. If the +base_url+ varaible is set then it is prepended
144
174
  # to the +url+ parameter. Any custom headers are merged with the contents
145
175
  # of the +headers+ instance variable. The results are returned in a
146
176
  # Response object.
147
- # Notice: this method doesn't accept any +data+ argument: if you need to send data with
148
- # a get request, please, use the #request method.
177
+ # Notice: this method doesn't accept any `data` argument: if you need to send a request body
178
+ # with a GET request, when using ElasticSearch for example, please, use the #request method.
179
+ #
180
+ # @param url[String] the URL to fetch
181
+ # @param headers[Hash] the hash of header keys to values
182
+ # @return [Patron::Response]
149
183
  def get(url, headers = {})
150
184
  request(:get, url, headers)
151
185
  end
152
186
 
153
187
  # Retrieve the contents of the specified +url+ as with #get, but the
154
- # content at the URL is downloaded directly into the specified file.
188
+ # content at the URL is downloaded directly into the specified file. The file will be accessed
189
+ # by libCURL bypassing the Ruby runtime entirely.
190
+ #
191
+ # Note that when using this option, the Response object will have ++nil++ as the body, and you
192
+ # will need to read your target file for access to the body string).
193
+ #
194
+ # @param url[String] the URL to fetch
195
+ # @param filename[String] path to the file to save the response body in
196
+ # @return [Patron::Response]
155
197
  def get_file(url, filename, headers = {})
156
198
  request(:get, url, headers, :file => filename)
157
199
  end
158
200
 
159
- # As #get but sends an HTTP HEAD request.
201
+ # Same as #get but performs a HEAD request.
202
+ #
203
+ # @see #get
204
+ # @param url[String] the URL to fetch
205
+ # @param headers[Hash] the hash of header keys to values
206
+ # @return [Patron::Response]
160
207
  def head(url, headers = {})
161
208
  request(:head, url, headers)
162
209
  end
163
210
 
164
- # As #get but sends an HTTP DELETE request.
165
- # Notice: this method doesn't accept any +data+ argument: if you need to send data with
166
- # a delete request, please, use the #request method.
211
+ # Same as #get but performs a DELETE request.
212
+ #
213
+ # Notice: this method doesn't accept any `data` argument: if you need to send data with
214
+ # a delete request (as might be needed for ElasticSearch), please, use the #request method.
215
+ #
216
+ # @param url[String] the URL to fetch
217
+ # @param headers[Hash] the hash of header keys to values
218
+ # @return [Patron::Response]
167
219
  def delete(url, headers = {})
168
220
  request(:delete, url, headers)
169
221
  end
170
222
 
171
- # Uploads the passed +data+ to the specified +url+ using HTTP PUT. +data+
172
- # must be a string.
223
+ # Uploads the passed `data` to the specified `url` using an HTTP PUT. Note that
224
+ # unline ++post++, a Hash is not accepted as the ++data++ argument.
225
+ #
226
+ # @todo inconsistency with "post" - Hash not accepted
227
+ # @param url[String] the URL to fetch
228
+ # @param data[#to_s] an object that can be converted to a String to create the request body
229
+ # @param headers[Hash] the hash of header keys to values
230
+ # @return [Patron::Response]
173
231
  def put(url, data, headers = {})
174
232
  request(:put, url, headers, :data => data)
175
233
  end
176
234
 
177
- # Uploads the contents of a file to the specified +url+ using HTTP PUT.
235
+ # Uploads the contents of `file` to the specified `url` using an HTTP PUT. The file will be
236
+ # sent "as-is" without any multipart encoding.
237
+ #
238
+ # @param url[String] the URL to fetch
239
+ # @param filename[String] path to the file to be uploaded
240
+ # @param headers[Hash] the hash of header keys to values
241
+ # @return [Patron::Response]
178
242
  def put_file(url, filename, headers = {})
179
243
  request(:put, url, headers, :file => filename)
180
244
  end
181
245
 
182
- # Uploads the passed +data+ to the specified +url+ using HTTP POST. +data+
183
- # can be a string or a hash.
246
+ # Uploads the passed `data` to the specified `url` using an HTTP POST.
247
+ #
248
+ # @param url[String] the URL to fetch
249
+ # @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
250
+ # @param headers[Hash] the hash of header keys to values
251
+ # @return [Patron::Response]
184
252
  def post(url, data, headers = {})
185
253
  if data.is_a?(Hash)
186
254
  data = data.map {|k,v| urlencode(k.to_s) + '=' + urlencode(v.to_s) }.join('&')
@@ -189,31 +257,52 @@ module Patron
189
257
  request(:post, url, headers, :data => data)
190
258
  end
191
259
 
192
- # Uploads the contents of a file to the specified +url+ using HTTP POST.
260
+ # Uploads the contents of `file` to the specified `url` using an HTTP POST.
261
+ # The file will be sent "as-is" without any multipart encoding.
262
+ #
263
+ # @param url[String] the URL to fetch
264
+ # @param filename[String] path to the file to be uploaded
265
+ # @param headers[Hash] the hash of header keys to values
266
+ # @return [Patron::Response]
193
267
  def post_file(url, filename, headers = {})
194
268
  request(:post, url, headers, :file => filename)
195
269
  end
196
270
 
197
- # Uploads the contents of a file and data to the specified +url+ using HTTP POST.
271
+ # Uploads the contents of `filename` to the specified `url` using an HTTP POST,
272
+ # in combination with given form fields passed in `data`.
273
+ #
274
+ # @param url[String] the URL to fetch
275
+ # @param data[Hash] hash of the form fields
276
+ # @param filename[String] path to the file to be uploaded
277
+ # @param headers[Hash] the hash of header keys to values
278
+ # @return [Patron::Response]
198
279
  def post_multipart(url, data, filename, headers = {})
199
280
  request(:post, url, headers, {:data => data, :file => filename, :multipart => true})
200
281
  end
201
282
 
202
- ###################################################################
203
- ### WebDAV methods
204
- ###
205
283
 
284
+ # @!group WebDAV methods
206
285
  # Sends a WebDAV COPY request to the specified +url+.
286
+ #
287
+ # @param url[String] the URL to copy
288
+ # @param dest[String] the URL of the COPY destination
289
+ # @param headers[Hash] the hash of header keys to values
290
+ # @return [Patron::Response]
207
291
  def copy(url, dest, headers = {})
208
292
  headers['Destination'] = dest
209
293
  request(:copy, url, headers)
210
294
  end
211
-
212
- ###################################################################
213
- ### Basic API methods
214
- ###
215
-
216
- # Send an HTTP request to the specified +url+.
295
+ # @!endgroup
296
+
297
+ # @!group Basic API methods
298
+ # Send an HTTP request to the specified `url`.
299
+ #
300
+ # @param action[#to_s] the HTTP verb
301
+ # @param url[String] the URL for the request
302
+ # @param headers[Hash] headers to send along with the request
303
+ # @param options[Hash] any additonal setters to call on the Request
304
+ # @see Patron::Request
305
+ # @return [Patron::Response]
217
306
  def request(action, url, headers, options = {})
218
307
  req = build_request(action, url, headers, options)
219
308
  handle_request(req)
@@ -227,11 +316,22 @@ module Patron
227
316
  # various headers/status codes. The method must return
228
317
  # a module that supports the same interface for +new+
229
318
  # as ++Patron::Response++
319
+ #
320
+ # @return [#new] Returns any object that responds to `.new` with 6 arguments
321
+ # @see Patron::Response#initialize
230
322
  def response_class
231
323
  ::Patron::Response
232
324
  end
233
325
 
234
- # Build a request object that can be used in +handle_request+
326
+ # Builds a request object that can be used by ++handle_request++
327
+ # Note that internally, ++handle_request++ uses instance variables of
328
+ # the Request object, and not it's public methods.
329
+ #
330
+ # @param action[String] the HTTP verb
331
+ # @paran url[#to_s] the addition to the base url component, or a complete URL
332
+ # @paran headers[Hash] a hash of headers, "Accept" will be automatically set to an empty string if not provided
333
+ # @paran options[Hash] any overriding options (will shadow the options from the Session object)
334
+ # @return [Patron::Request] the request that will be passed to ++handle_request++
235
335
  def build_request(action, url, headers, options = {})
236
336
  # If the Expect header isn't set uploads are really slow
237
337
  headers['Expect'] ||= ''
@@ -270,5 +370,6 @@ module Patron
270
370
  req.url = url
271
371
  end
272
372
  end
373
+ # @!endgroup
273
374
  end
274
375
  end
@@ -23,6 +23,7 @@
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
25
 
26
+
26
27
  module Patron
27
28
  module Util
28
29
  extend self
@@ -1,3 +1,3 @@
1
1
  module Patron
2
- VERSION = "0.6.0"
2
+ VERSION = "0.6.1"
3
3
  end
@@ -18,6 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.add_development_dependency "rake-compiler", ">= 0.7.5"
19
19
  s.add_development_dependency "rspec", ">= 2.3.0"
20
20
  s.add_development_dependency "simplecov", ">= 0.10.0"
21
+ s.add_development_dependency "yard", "~> 0.8"
21
22
 
22
23
  s.files = `git ls-files`.split("\n")
23
24
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
@@ -21,6 +21,8 @@
21
21
  ## THE SOFTWARE.
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
+
25
+
24
26
  require File.expand_path("./spec") + '/spec_helper.rb'
25
27
 
26
28
  describe Patron do
@@ -21,6 +21,8 @@
21
21
  ## THE SOFTWARE.
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
+
25
+
24
26
  require File.expand_path("./spec") + '/spec_helper.rb'
25
27
 
26
28
 
@@ -1,3 +1,6 @@
1
+ # -*- coding: UTF-8 -*-
2
+ # Encoding pragma is needed for loading this test properly on Ruby < 2.0
3
+
1
4
  ## -------------------------------------------------------------------
2
5
  ##
3
6
  ## Copyright (c) 2009 Phillip Toland <phil.toland@gmail.com>
@@ -21,6 +24,8 @@
21
24
  ## THE SOFTWARE.
22
25
  ##
23
26
  ## -------------------------------------------------------------------
27
+
28
+
24
29
  require File.expand_path("./spec") + '/spec_helper.rb'
25
30
  require 'webrick'
26
31
  require 'base64'
@@ -21,6 +21,8 @@
21
21
  ## THE SOFTWARE.
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
+
25
+
24
26
  require File.expand_path("./spec") + '/spec_helper.rb'
25
27
  require 'webrick'
26
28
  require 'yaml'
@@ -286,6 +288,18 @@ describe Patron::Session do
286
288
  expect(body.header['authorization']).to be == [encode_authz("foo", "bar")]
287
289
  end
288
290
 
291
+ it "should store cookies across multiple requests" do
292
+ tf = Tempfile.new('cookiejar')
293
+ cookie_jar_path = tf.path
294
+
295
+ @session.handle_cookies(cookie_jar_path)
296
+ response = @session.get("/setcookie").body
297
+
298
+ cookie_jar_contents = tf.read
299
+ expect(cookie_jar_contents).not_to be_empty
300
+ expect(cookie_jar_contents).to include('Netscape HTTP Cookie File')
301
+ end
302
+
289
303
  it "should handle cookies if set" do
290
304
  @session.handle_cookies
291
305
  response = @session.get("/setcookie").body
@@ -471,10 +485,12 @@ describe Patron::Session do
471
485
  it 'it should not clobber stderr' do
472
486
  rdev = STDERR.stat.rdev
473
487
 
474
- @session.enable_debug
488
+ retval = @session.enable_debug
489
+ expect(retval).to eq(@session)
475
490
  expect(STDERR.stat.rdev).to be == rdev
476
491
 
477
- @session.enable_debug
492
+ retval = @session.enable_debug
493
+ expect(retval).to eq(@session)
478
494
  expect(STDERR.stat.rdev).to be == rdev
479
495
  end
480
496
  end
@@ -21,6 +21,8 @@
21
21
  ## THE SOFTWARE.
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
+
25
+
24
26
  require File.expand_path("./spec") + '/spec_helper.rb'
25
27
  require 'webrick'
26
28
  require 'yaml'
@@ -267,6 +269,15 @@ describe Patron::Session do
267
269
  end
268
270
  end
269
271
 
272
+ it "should raise when an unsupported or unknown SSL version is requested" do
273
+ ['something', 1].each do |version|
274
+ @session.ssl_version = version
275
+ expect {
276
+ @session.get("/test")
277
+ }.to raise_error(Patron::UnsupportedSSLVersion)
278
+ end
279
+ end
280
+
270
281
  # ------------------------------------------------------------------------
271
282
  describe 'when debug is enabled' do
272
283
  it 'it should not clobber stderr' do
@@ -21,6 +21,8 @@
21
21
  ## THE SOFTWARE.
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
+
25
+
24
26
  if ENV["COVERAGE"]
25
27
  require 'simplecov'
26
28
  SimpleCov.start do
@@ -22,6 +22,8 @@
22
22
  ## THE SOFTWARE.
23
23
  ##
24
24
  ## -------------------------------------------------------------------
25
+
26
+
25
27
  require 'yaml'
26
28
  require 'webrick'
27
29
  require 'webrick/https'
@@ -21,6 +21,8 @@
21
21
  ## THE SOFTWARE.
22
22
  ##
23
23
  ## -------------------------------------------------------------------
24
+
25
+
24
26
  require File.expand_path("./spec") + '/spec_helper.rb'
25
27
 
26
28
  describe Patron::Util do
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.0
4
+ version: 0.6.1
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-04-09 00:00:00.000000000 Z
11
+ date: 2016-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.10.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
69
83
  description: Ruby HTTP client library based on libcurl
70
84
  email:
71
85
  - phil.toland@gmail.com
@@ -77,6 +91,7 @@ files:
77
91
  - ".autotest"
78
92
  - ".gitignore"
79
93
  - ".rspec"
94
+ - ".travis.yml"
80
95
  - Gemfile
81
96
  - Gemfile.lock
82
97
  - LICENSE
@@ -135,3 +150,4 @@ signing_key:
135
150
  specification_version: 4
136
151
  summary: Patron HTTP Client
137
152
  test_files: []
153
+ has_rdoc: