rest-client 1.6.7 → 1.6.8.rc1

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.

Potentially problematic release.


This version of rest-client might be problematic. Click here for more details.

@@ -9,14 +9,14 @@ module RestClient
9
9
  def generate(params)
10
10
  if params.is_a?(String)
11
11
  Base.new(params)
12
- elsif params.respond_to?(:read)
13
- Streamed.new(params)
14
- elsif params
12
+ elsif params.is_a?(Hash)
15
13
  if params.delete(:multipart) == true || has_file?(params)
16
14
  Multipart.new(params)
17
15
  else
18
16
  UrlEncoded.new(params)
19
17
  end
18
+ elsif params.respond_to?(:read)
19
+ Streamed.new(params)
20
20
  else
21
21
  nil
22
22
  end
@@ -44,7 +44,7 @@ module RestClient
44
44
  has_file_array?(v)
45
45
  else
46
46
  v.respond_to?(:path) && v.respond_to?(:read)
47
- end
47
+ end
48
48
  end
49
49
  end
50
50
 
@@ -147,12 +147,17 @@ module RestClient
147
147
 
148
148
  # for UrlEncoded escape the keys
149
149
  def handle_key key
150
- URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
150
+ parser.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
151
151
  end
152
152
 
153
153
  def headers
154
154
  super.merge({'Content-Type' => 'application/x-www-form-urlencoded'})
155
155
  end
156
+
157
+ private
158
+ def parser
159
+ URI.const_defined?(:Parser) ? URI::Parser.new : URI
160
+ end
156
161
  end
157
162
 
158
163
  class Multipart < Base
@@ -0,0 +1,29 @@
1
+ module RestClient
2
+ module Platform
3
+ # Return true if we are running on a darwin-based Ruby platform. This will
4
+ # be false for jruby even on OS X.
5
+ #
6
+ # @return [Boolean]
7
+ def self.mac?
8
+ RUBY_PLATFORM.include?('darwin')
9
+ end
10
+
11
+ # Return true if we are running on Windows.
12
+ #
13
+ # @return [Boolean]
14
+ #
15
+ def self.windows?
16
+ # Ruby only sets File::ALT_SEPARATOR on Windows, and the Ruby standard
17
+ # library uses that to test what platform it's on.
18
+ !!File::ALT_SEPARATOR
19
+ end
20
+
21
+ # Return true if we are running on jruby.
22
+ #
23
+ # @return [Boolean]
24
+ #
25
+ def self.jruby?
26
+ RUBY_PLATFORM == 'java'
27
+ end
28
+ end
29
+ end
@@ -22,12 +22,14 @@ module RestClient
22
22
  # * :verify_ssl enable ssl verification, possible values are constants from OpenSSL::SSL
23
23
  # * :timeout and :open_timeout passing in -1 will disable the timeout by setting the corresponding net timeout values to nil
24
24
  # * :ssl_client_cert, :ssl_client_key, :ssl_ca_file
25
+ # * :ssl_verify_callback, :ssl_verify_callback_warnings
25
26
  class Request
26
27
 
27
28
  attr_reader :method, :url, :headers, :cookies,
28
29
  :payload, :user, :password, :timeout, :max_redirects,
29
30
  :open_timeout, :raw_response, :verify_ssl, :ssl_client_cert,
30
- :ssl_client_key, :ssl_ca_file, :processed_headers, :args
31
+ :ssl_client_key, :ssl_ca_file, :processed_headers, :args,
32
+ :ssl_verify_callback, :ssl_verify_callback_warnings
31
33
 
32
34
  def self.execute(args, & block)
33
35
  new(args).execute(& block)
@@ -53,6 +55,8 @@ module RestClient
53
55
  @ssl_client_cert = args[:ssl_client_cert] || nil
54
56
  @ssl_client_key = args[:ssl_client_key] || nil
55
57
  @ssl_ca_file = args[:ssl_ca_file] || nil
58
+ @ssl_verify_callback = args[:ssl_verify_callback] || nil
59
+ @ssl_verify_callback_warnings = args.fetch(:ssl_verify_callback, true)
56
60
  @tf = nil # If you are a raw request, this is your tempfile
57
61
  @max_redirects = args[:max_redirects] || 10
58
62
  @processed_headers = make_headers headers
@@ -129,29 +133,40 @@ module RestClient
129
133
  if p[k].is_a? Hash
130
134
  process_payload(p[k], key)
131
135
  else
132
- value = URI.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
136
+ value = parser.escape(p[k].to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
133
137
  "#{key}=#{value}"
134
138
  end
135
139
  end.join("&")
136
140
  end
137
141
  end
138
142
 
143
+ def print_verify_callback_warnings
144
+ warned = false
145
+ if RestClient::Platform.mac?
146
+ warn('warning: ssl_verify_callback return code is ignored on OS X')
147
+ warned = true
148
+ end
149
+ if RestClient::Platform.jruby?
150
+ warn('warning: SSL verify_callback may not work correctly in jruby')
151
+ warn('see https://github.com/jruby/jruby/issues/597')
152
+ warned = true
153
+ end
154
+ warned
155
+ end
156
+
139
157
  def transmit uri, req, payload, & block
140
158
  setup_credentials req
141
159
 
142
160
  net = net_http_class.new(uri.host, uri.port)
143
161
  net.use_ssl = uri.is_a?(URI::HTTPS)
144
- if (@verify_ssl == false) || (@verify_ssl == OpenSSL::SSL::VERIFY_NONE)
145
- net.verify_mode = OpenSSL::SSL::VERIFY_NONE
146
- elsif @verify_ssl.is_a? Integer
147
- net.verify_mode = @verify_ssl
148
- net.verify_callback = lambda do |preverify_ok, ssl_context|
149
- if (!preverify_ok) || ssl_context.error != 0
150
- err_msg = "SSL Verification failed -- Preverify: #{preverify_ok}, Error: #{ssl_context.error_string} (#{ssl_context.error})"
151
- raise SSLCertificateNotVerified.new(err_msg)
152
- end
153
- true
162
+ if @verify_ssl
163
+ if @verify_ssl.is_a? Integer
164
+ net.verify_mode = @verify_ssl
165
+ else
166
+ net.verify_mode = OpenSSL::SSL::VERIFY_PEER
154
167
  end
168
+ else
169
+ net.verify_mode = OpenSSL::SSL::VERIFY_NONE
155
170
  end
156
171
  net.cert = @ssl_client_cert if @ssl_client_cert
157
172
  net.key = @ssl_client_key if @ssl_client_key
@@ -161,7 +176,26 @@ module RestClient
161
176
 
162
177
  # disable the timeout if the timeout value is -1
163
178
  net.read_timeout = nil if @timeout == -1
164
- net.out_timeout = nil if @open_timeout == -1
179
+ net.open_timeout = nil if @open_timeout == -1
180
+
181
+ # verify_callback isn't well supported on all platforms, but do allow
182
+ # users to set one if they want.
183
+ if ssl_verify_callback
184
+ net.verify_callback = ssl_verify_callback
185
+
186
+ # Hilariously, jruby only calls the callback when cert_store is set to
187
+ # something, so make sure to set one.
188
+ # https://github.com/jruby/jruby/issues/597
189
+ if RestClient::Platform.jruby?
190
+ net.cert_store ||= OpenSSL::X509::Store.new
191
+ end
192
+
193
+ if ssl_verify_callback_warnings != false
194
+ if print_verify_callback_warnings
195
+ warn('pass :ssl_verify_callback_warnings => false to silence this')
196
+ end
197
+ end
198
+ end
165
199
 
166
200
  RestClient.before_execution_procs.each do |before_proc|
167
201
  before_proc.call(req, args)
@@ -182,6 +216,11 @@ module RestClient
182
216
  raise RestClient::ServerBrokeConnection
183
217
  rescue Timeout::Error
184
218
  raise RestClient::RequestTimeout
219
+ rescue OpenSSL::SSL::SSLError => error
220
+ # UGH. Not sure if this is needed at all. SSLCertificateNotVerified is not being used internally.
221
+ # I think it would be better to leave SSLError processing to the client (they'd have to do that anyway...)
222
+ raise SSLCertificateNotVerified.new(error.message) if error.message.include?("certificate verify failed")
223
+ raise error
185
224
  end
186
225
 
187
226
  def setup_credentials(req)
@@ -295,6 +334,11 @@ module RestClient
295
334
  {:accept => '*/*; q=0.5, application/xml', :accept_encoding => 'gzip, deflate'}
296
335
  end
297
336
 
337
+ private
338
+ def parser
339
+ URI.const_defined?(:Parser) ? URI::Parser.new : URI
340
+ end
341
+
298
342
  end
299
343
  end
300
344
 
@@ -6,7 +6,9 @@ module RestClient
6
6
 
7
7
  include AbstractResponse
8
8
 
9
- attr_accessor :args, :body, :net_http_res
9
+ attr_accessor :args, :net_http_res
10
+
11
+ attr_writer :body
10
12
 
11
13
  def body
12
14
  self
@@ -0,0 +1,7 @@
1
+ module RestClient
2
+ VERSION = '1.6.8.rc1' unless defined?(self::VERSION)
3
+
4
+ def self.version
5
+ VERSION
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path("../lib/restclient/version", __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'rest-client'
7
+ s.version = RestClient::VERSION
8
+ s.authors = ['REST Client Team']
9
+ s.description = 'A simple HTTP and REST client for Ruby, inspired by the Sinatra microframework style of specifying actions: get, put, post, delete.'
10
+ s.license = 'MIT'
11
+ s.email = 'rest.client@librelist.com'
12
+ s.executables = ['restclient']
13
+ s.extra_rdoc_files = ["README.rdoc", "history.md"]
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- spec/*`.split("\n")
16
+ s.homepage = 'https://github.com/rest-client/rest-client'
17
+ s.summary = 'Simple HTTP and REST client for Ruby, inspired by microframework syntax for specifying actions.'
18
+
19
+ s.add_dependency(%q<mime-types>, ["~> 1.16"])
20
+ s.add_dependency(%q<rdoc>, [">= 2.4.2"])
21
+ s.add_development_dependency(%q<rake>, ["~> 10.0"])
22
+ s.add_development_dependency(%q<webmock>, ["~> 1.4"])
23
+ s.add_development_dependency(%q<rspec>, ["~> 2.4"])
24
+ s.add_development_dependency(%q<pry>)
25
+ end
26
+
@@ -16,55 +16,55 @@ describe RestClient::AbstractResponse do
16
16
  end
17
17
 
18
18
  before do
19
- @net_http_res = mock('net http response')
19
+ @net_http_res = double('net http response')
20
20
  @response = MyAbstractResponse.new(@net_http_res, {})
21
21
  end
22
22
 
23
23
  it "fetches the numeric response code" do
24
24
  @net_http_res.should_receive(:code).and_return('200')
25
- @response.code.should == 200
25
+ @response.code.should eq 200
26
26
  end
27
27
 
28
28
  it "has a nice description" do
29
29
  @net_http_res.should_receive(:to_hash).and_return({'Content-Type' => ['application/pdf']})
30
30
  @net_http_res.should_receive(:code).and_return('200')
31
- @response.description == '200 OK | application/pdf bytes\n'
31
+ @response.description.should eq "200 OK | application/pdf bytes\n"
32
32
  end
33
33
 
34
34
  it "beautifies the headers by turning the keys to symbols" do
35
35
  h = RestClient::AbstractResponse.beautify_headers('content-type' => [ 'x' ])
36
- h.keys.first.should == :content_type
36
+ h.keys.first.should eq :content_type
37
37
  end
38
38
 
39
39
  it "beautifies the headers by turning the values to strings instead of one-element arrays" do
40
40
  h = RestClient::AbstractResponse.beautify_headers('x' => [ 'text/html' ] )
41
- h.values.first.should == 'text/html'
41
+ h.values.first.should eq 'text/html'
42
42
  end
43
43
 
44
44
  it "fetches the headers" do
45
45
  @net_http_res.should_receive(:to_hash).and_return('content-type' => [ 'text/html' ])
46
- @response.headers.should == { :content_type => 'text/html' }
46
+ @response.headers.should eq({ :content_type => 'text/html' })
47
47
  end
48
48
 
49
49
  it "extracts cookies from response headers" do
50
50
  @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=1; path=/'])
51
- @response.cookies.should == { 'session_id' => '1' }
51
+ @response.cookies.should eq({ 'session_id' => '1' })
52
52
  end
53
53
 
54
54
  it "extract strange cookies" do
55
55
  @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=ZJ/HQVH6YE+rVkTpn0zvTQ==; path=/'])
56
- @response.cookies.should == { 'session_id' => 'ZJ%2FHQVH6YE+rVkTpn0zvTQ%3D%3D' }
56
+ @response.cookies.should eq({ 'session_id' => 'ZJ%2FHQVH6YE+rVkTpn0zvTQ%3D%3D' })
57
57
  end
58
58
 
59
59
  it "doesn't escape cookies" do
60
60
  @net_http_res.should_receive(:to_hash).and_return('set-cookie' => ['session_id=BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca; path=/'])
61
- @response.cookies.should == { 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' }
61
+ @response.cookies.should eq({ 'session_id' => 'BAh7BzoNYXBwX25hbWUiEGFwcGxpY2F0aW9uOgpsb2dpbiIKYWRtaW4%3D%0A--08114ba654f17c04d20dcc5228ec672508f738ca' })
62
62
  end
63
63
 
64
64
  it "can access the net http result directly" do
65
- @response.net_http_res.should == @net_http_res
65
+ @response.net_http_res.should eq @net_http_res
66
66
  end
67
-
67
+
68
68
  describe "#return!" do
69
69
  it "should return the response itself on 200-codes" do
70
70
  @net_http_res.should_receive(:code).and_return('200')
@@ -75,7 +75,7 @@ describe RestClient::AbstractResponse do
75
75
  @net_http_res.should_receive(:code).and_return('1000')
76
76
  lambda { @response.return! }.should raise_error RestClient::RequestFailed
77
77
  end
78
-
78
+
79
79
  it "should raise an error on a redirection after non-GET/HEAD requests" do
80
80
  @net_http_res.should_receive(:code).and_return('301')
81
81
  @response.args.merge(:method => :put)
data/spec/base.rb CHANGED
@@ -1,11 +1,8 @@
1
1
  def is_ruby_19?
2
- RUBY_VERSION == '1.9.1' or RUBY_VERSION == '1.9.2'
2
+ RUBY_VERSION > '1.9'
3
3
  end
4
4
 
5
- Encoding.default_internal = Encoding.default_external = "ASCII-8BIT" if is_ruby_19?
6
-
7
5
  require 'rubygems'
8
- require 'spec'
9
6
 
10
7
  begin
11
8
  require "ruby-debug"
@@ -1,23 +1,23 @@
1
1
  require File.join( File.dirname(File.expand_path(__FILE__)), 'base')
2
2
 
3
3
  require 'webmock/rspec'
4
- include WebMock
4
+ include WebMock::API
5
5
 
6
6
  describe RestClient::Exception do
7
7
  it "returns a 'message' equal to the class name if the message is not set, because 'message' should not be nil" do
8
8
  e = RestClient::Exception.new
9
- e.message.should == "RestClient::Exception"
9
+ e.message.should eq "RestClient::Exception"
10
10
  end
11
-
11
+
12
12
  it "returns the 'message' that was set" do
13
13
  e = RestClient::Exception.new
14
14
  message = "An explicitly set message"
15
15
  e.message = message
16
- e.message.should == message
16
+ e.message.should eq message
17
17
  end
18
-
18
+
19
19
  it "sets the exception message to ErrorMessage" do
20
- RestClient::ResourceNotFound.new.message.should == 'Resource Not Found'
20
+ RestClient::ResourceNotFound.new.message.should eq 'Resource Not Found'
21
21
  end
22
22
 
23
23
  it "contains exceptions in RestClient" do
@@ -29,13 +29,13 @@ end
29
29
  describe RestClient::ServerBrokeConnection do
30
30
  it "should have a default message of 'Server broke connection'" do
31
31
  e = RestClient::ServerBrokeConnection.new
32
- e.message.should == 'Server broke connection'
32
+ e.message.should eq 'Server broke connection'
33
33
  end
34
34
  end
35
35
 
36
36
  describe RestClient::RequestFailed do
37
37
  before do
38
- @response = mock('HTTP Response', :code => '502')
38
+ @response = double('HTTP Response', :code => '502')
39
39
  end
40
40
 
41
41
  it "stores the http response on the exception" do
@@ -43,17 +43,17 @@ describe RestClient::RequestFailed do
43
43
  begin
44
44
  raise RestClient::RequestFailed, response
45
45
  rescue RestClient::RequestFailed => e
46
- e.response.should == response
46
+ e.response.should eq response
47
47
  end
48
48
  end
49
49
 
50
50
  it "http_code convenience method for fetching the code as an integer" do
51
- RestClient::RequestFailed.new(@response).http_code.should == 502
51
+ RestClient::RequestFailed.new(@response).http_code.should eq 502
52
52
  end
53
53
 
54
54
  it "http_body convenience method for fetching the body (decoding when necessary)" do
55
- RestClient::RequestFailed.new(@response).http_code.should == 502
56
- RestClient::RequestFailed.new(@response).message.should == 'HTTP status code 502'
55
+ RestClient::RequestFailed.new(@response).http_code.should eq 502
56
+ RestClient::RequestFailed.new(@response).message.should eq 'HTTP status code 502'
57
57
  end
58
58
 
59
59
  it "shows the status code in the message" do
@@ -67,22 +67,22 @@ describe RestClient::ResourceNotFound do
67
67
  begin
68
68
  raise RestClient::ResourceNotFound, response
69
69
  rescue RestClient::ResourceNotFound => e
70
- e.response.should == response
70
+ e.response.should eq response
71
71
  end
72
72
  end
73
73
  end
74
74
 
75
75
  describe "backwards compatibility" do
76
76
  it "alias RestClient::Request::Redirect to RestClient::Redirect" do
77
- RestClient::Request::Redirect.should == RestClient::Redirect
77
+ RestClient::Request::Redirect.should eq RestClient::Redirect
78
78
  end
79
79
 
80
80
  it "alias RestClient::Request::Unauthorized to RestClient::Unauthorized" do
81
- RestClient::Request::Unauthorized.should == RestClient::Unauthorized
81
+ RestClient::Request::Unauthorized.should eq RestClient::Unauthorized
82
82
  end
83
83
 
84
84
  it "alias RestClient::Request::RequestFailed to RestClient::RequestFailed" do
85
- RestClient::Request::RequestFailed.should == RestClient::RequestFailed
85
+ RestClient::Request::RequestFailed.should eq RestClient::RequestFailed
86
86
  end
87
87
 
88
88
  it "make the exception's response act like an Net::HTTPResponse" do
@@ -92,7 +92,7 @@ describe "backwards compatibility" do
92
92
  RestClient.get "www.example.com"
93
93
  raise
94
94
  rescue RestClient::ResourceNotFound => e
95
- e.response.body.should == body
95
+ e.response.body.should eq body
96
96
  end
97
97
  end
98
98
  end
@@ -0,0 +1,19 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQG
3
+ EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMSsw
4
+ KQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5jZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAw
5
+ MFoXDTMxMTExMDAwMDAwMFowbDELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZ
6
+ MBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFu
7
+ Y2UgRVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm+9S75S0t
8
+ Mqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTWPNt0OKRKzE0lgvdKpVMS
9
+ OO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEMxChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3
10
+ MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFBIk5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQ
11
+ NAQTXKFx01p8VdteZOE3hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUe
12
+ h10aUAsgEsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
13
+ Af8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaAFLE+w2kD+L9HAdSY
14
+ JhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3NecnzyIZgYIVyHbIUf4KmeqvxgydkAQ
15
+ V8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6zeM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFp
16
+ myPInngiK3BD41VHMWEZ71jFhS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkK
17
+ mNEVX58Svnw2Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
18
+ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep+OkuE6N36B9K
19
+ -----END CERTIFICATE-----