1
0
Fork 0
mirror of https://github.com/rest-client/rest-client.git synced 2022-11-09 13:49:40 -05:00

Block for response done, easier than expected!

This commit is contained in:
Julien Kirch 2010-01-22 21:04:49 +01:00
parent 80fc030a9b
commit 68ff7f840f
8 changed files with 478 additions and 372 deletions

View file

@ -49,6 +49,44 @@ See RestClient::Resource module docs for details.
See RestClient::Resource docs for details.
== Exceptions
* for results code between 200 and 206 a RestClient::Response will be returned
* for results code between 301 and 303 the redirection will be automatically followed
* for other result codes a RestClient::Exception holding the Response will be raised, a specific exception class will be thrown for know error codes
RestClient.get 'http://example.com/resource'
➔ RestClient::ResourceNotFound: RestClient::ResourceNotFound
begin
RestClient.get 'http://example.com/resource'
rescue => e
e.response
end
➔ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL..."
== Result handling
A block can be passed to the RestClient method, this block will then be called with the Response.
Response.return! can be called to invoke the default response's behavior (return the Response for 200..206, raise an exception in other cases).
# Don't raise exceptions but return the response
RestClient.get('http://example.com/resource'){|response| response}
➔ "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n<html><head>\n<title>404 Not Found</title>\n</head><body>\n<h1>Not Found</h1>\n<p>The requested URL..."
# Manage a specific error code
RestClient.get('http://my-rest-service.com/resource'){ |response|
case response.code
when 200
p "It worked !"
response
when 423
raise SomeCustomExceptionIfYouWant
else
response.return!
end
}
== Lower-level access
For cases not covered by the general API, you can use the RestClient::Resource class which provide a lower-level API, see the class' rdoc for more information.
@ -58,17 +96,17 @@ For cases not covered by the general API, you can use the RestClient::Resource c
The restclient shell command gives an IRB session with RestClient already loaded:
$ restclient
>> RestClient.get 'http://example.com'
RestClient.get 'http://example.com'
Specify a URL argument for get/post/put/delete on that resource:
$ restclient http://example.com
>> put '/resource', 'data'
put '/resource', 'data'
Add a user and password for authenticated resources:
$ restclient https://example.com user pass
>> delete '/private/resource'
delete '/private/resource'
Create ~/.restclient for named sessions:
@ -87,9 +125,9 @@ Then invoke:
== Meta
Written by Adam Wiggins, major modifications by Blake Mizerany, maintained by Archiloque
Written by Adam Wiggins, major modifications by Blake Mizerany, maintained by Julien Kirch
Patches contributed by: Chris Anderson, Greg Borenstein, Ardekantur, Pedro Belo, Rafael Souza, Rick Olson, Aman Gupta, François Beausoleil and Nick Plante.
Patches contributed by many, including Chris Anderson, Greg Borenstein, Ardekantur, Pedro Belo, Rafael Souza, Rick Olson, Aman Gupta, François Beausoleil and Nick Plante.
Released under the MIT License: http://www.opensource.org/licenses/mit-license.php

View file

@ -1,9 +1,10 @@
# 1.2.1
- a block can be used to process a request's result, this enable to handle custom error codes or paththrought (design by Cyril Rohr)
- cleaner log API, add a warning for some cases but should be compatible
- accept multiple "Set-Cookie" headers, see http://www.ietf.org/rfc/rfc2109.txt (patch provided by Cyril Rohr)
- remove "Content-Length" and "Content-Type" headers when following a redirection (patch provided by haarts)
- all http error codes has now a corresponding exception class and all of them contain the Reponse
- all http error codes have now a corresponding exception class and all of them contain the Reponse
# 1.2.0

View file

@ -64,24 +64,24 @@ require File.dirname(__FILE__) + '/restclient/net_http_ext'
#
module RestClient
def self.get(url, headers={})
Request.execute(:method => :get, :url => url, :headers => headers)
def self.get(url, headers={}, &block)
Request.execute(:method => :get, :url => url, :headers => headers, &block)
end
def self.post(url, payload, headers={})
Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers)
def self.post(url, payload, headers={}, &block)
Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, &block)
end
def self.put(url, payload, headers={})
Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers)
def self.put(url, payload, headers={}, &block)
Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, &block)
end
def self.delete(url, headers={})
Request.execute(:method => :delete, :url => url, :headers => headers)
def self.delete(url, headers={}, &block)
Request.execute(:method => :delete, :url => url, :headers => headers, &block)
end
def self.head(url, headers={})
Request.execute(:method => :head, :url => url, :headers => headers)
def self.head(url, headers={}, &block)
Request.execute(:method => :head, :url => url, :headers => headers, &block)
end
class << self

View file

@ -34,7 +34,11 @@ module RestClient
EXCEPTIONS_MAP = {}
end
{304 => 'Not Modified',
{300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
400 => 'Bad Request',
401 => 'Unauthorized',

View file

@ -35,6 +35,18 @@ module RestClient
end
end
# Return the default behavior corresponding to the response code:
# the response itself for code in 200..206 and an exception in other cases
def return!
if (200..206).include? code
self
elsif Exceptions::EXCEPTIONS_MAP[code]
raise Exceptions::EXCEPTIONS_MAP[code], self
else
raise RequestFailed, self
end
end
def self.included(receiver)
receiver.extend(RestClient::Mixin::Response::ClassMethods)
end

View file

@ -21,19 +21,17 @@ module RestClient
# * :ssl_client_cert, :ssl_client_key, :ssl_ca_file
class Request
include RestClient::Exceptions
attr_reader :method, :url, :payload, :headers, :processed_headers,
:cookies, :user, :password, :timeout, :open_timeout,
:verify_ssl, :ssl_client_cert, :ssl_client_key, :ssl_ca_file,
:raw_response
def self.execute(args)
new(args).execute
def self.execute(args, &block)
new(args).execute &block
end
def initialize(args)
def initialize args
@method = args[:method] or raise ArgumentError, "must pass :method"
@url = args[:url] or raise ArgumentError, "must pass :url"
@headers = args[:headers] || {}
@ -52,20 +50,20 @@ module RestClient
@processed_headers = make_headers headers
end
def execute
execute_inner
def execute &block
execute_inner &block
rescue Redirect => e
@processed_headers.delete("Content-Length")
@processed_headers.delete("Content-Type")
@processed_headers.delete "Content-Length"
@processed_headers.delete "Content-Type"
@url = e.url
@method = :get
@payload = nil
execute
execute &block
end
def execute_inner
def execute_inner &block
uri = parse_url_with_auth(url)
transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload
transmit uri, net_http_request_class(method).new(uri.request_uri, processed_headers), payload, &block
end
def make_headers user_headers
@ -138,8 +136,8 @@ module RestClient
end
end
def transmit(uri, req, payload)
setup_credentials(req)
def transmit uri, req, payload, &block
setup_credentials req
net = net_http_class.new(uri.host, uri.port)
net.use_ssl = uri.is_a?(URI::HTTPS)
@ -159,7 +157,7 @@ module RestClient
net.start do |http|
res = http.request(req, payload) { |http_response| fetch_body(http_response) }
log_response res
process_result(res)
process_result res, &block
end
rescue EOFError
raise RestClient::ServerBrokeConnection
@ -179,7 +177,7 @@ module RestClient
@tf = Tempfile.new("rest-client")
size, total = 0, http_response.header['Content-Length'].to_i
http_response.read_body do |chunk|
@tf.write(chunk)
@tf.write chunk
size += chunk.size
if RestClient.log
if size == 0
@ -209,9 +207,7 @@ module RestClient
code = res.code.to_i
if (200..206).include? code
response
elsif (301..303).include? code
if (301..303).include? code
url = res.header['Location']
if url !~ /^http/
@ -220,10 +216,12 @@ module RestClient
url = uri.to_s
end
raise Redirect, url
elsif EXCEPTIONS_MAP[code]
raise EXCEPTIONS_MAP[code], response
else
raise RequestFailed, response
if block_given?
yield response
else
response.return!
end
end
end

View file

@ -22,20 +22,22 @@ describe RestClient::Request do
@request.default_headers[:accept].should == '*/*; q=0.5, application/xml'
end
it "decodes an uncompressed result body by passing it straight through" do
RestClient::Request.decode(nil, 'xyz').should == 'xyz'
end
describe "compression" do
it "decodes an uncompressed result body by passing it straight through" do
RestClient::Request.decode(nil, 'xyz').should == 'xyz'
end
it "decodes a gzip body" do
RestClient::Request.decode('gzip', "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000").should == "i'm gziped\n"
end
it "decodes a gzip body" do
RestClient::Request.decode('gzip', "\037\213\b\b\006'\252H\000\003t\000\313T\317UH\257\312,HM\341\002\000G\242(\r\v\000\000\000").should == "i'm gziped\n"
end
it "ingores gzip for empty bodies" do
RestClient::Request.decode('gzip', '').should be_empty
end
it "ingores gzip for empty bodies" do
RestClient::Request.decode('gzip', '').should be_empty
end
it "decodes a deflated body" do
RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363").should == "some deflated text"
it "decodes a deflated body" do
RestClient::Request.decode('deflate', "x\234+\316\317MUHIM\313I,IMQ(I\255(\001\000A\223\006\363").should == "some deflated text"
end
end
it "processes a successful result" do
@ -66,19 +68,21 @@ describe RestClient::Request do
@request.parse_url('example.com/resource')
end
it "extracts the username and password when parsing http://user:password@example.com/" do
URI.stub!(:parse).and_return(mock('uri', :user => 'joe', :password => 'pass1'))
@request.parse_url_with_auth('http://joe:pass1@example.com/resource')
@request.user.should == 'joe'
@request.password.should == 'pass1'
end
describe "user - password" do
it "extracts the username and password when parsing http://user:password@example.com/" do
URI.stub!(:parse).and_return(mock('uri', :user => 'joe', :password => 'pass1'))
@request.parse_url_with_auth('http://joe:pass1@example.com/resource')
@request.user.should == 'joe'
@request.password.should == 'pass1'
end
it "doesn't overwrite user and password (which may have already been set by the Resource constructor) if there is no user/password in the url" do
URI.stub!(:parse).and_return(mock('uri', :user => nil, :password => nil))
@request = RestClient::Request.new(:method => 'get', :url => 'example.com', :user => 'beth', :password => 'pass2')
@request.parse_url_with_auth('http://example.com/resource')
@request.user.should == 'beth'
@request.password.should == 'pass2'
it "doesn't overwrite user and password (which may have already been set by the Resource constructor) if there is no user/password in the url" do
URI.stub!(:parse).and_return(mock('uri', :user => nil, :password => nil))
@request = RestClient::Request.new(:method => 'get', :url => 'example.com', :user => 'beth', :password => 'pass2')
@request.parse_url_with_auth('http://example.com/resource')
@request.user.should == 'beth'
@request.password.should == 'pass2'
end
end
it "correctly formats cookies provided to the constructor" do
@ -92,50 +96,55 @@ describe RestClient::Request do
@request.net_http_request_class(:put).should == Net::HTTP::Put
end
it "merges user headers with the default headers" do
@request.should_receive(:default_headers).and_return({ '1' => '2' })
headers = @request.make_headers('3' => '4')
headers.should have_key('1')
headers['1'].should == '2'
headers.should have_key('3')
headers['3'].should == '4'
describe "user headers" do
it "merges user headers with the default headers" do
@request.should_receive(:default_headers).and_return({ '1' => '2' })
headers = @request.make_headers('3' => '4')
headers.should have_key('1')
headers['1'].should == '2'
headers.should have_key('3')
headers['3'].should == '4'
end
it "prefers the user header when the same header exists in the defaults" do
@request.should_receive(:default_headers).and_return({ '1' => '2' })
headers = @request.make_headers('1' => '3')
headers.should have_key('1')
headers['1'].should == '3'
end
end
it "prefers the user header when the same header exists in the defaults" do
@request.should_receive(:default_headers).and_return({ '1' => '2' })
headers = @request.make_headers('1' => '3')
headers.should have_key('1')
headers['1'].should == '3'
end
describe "header symbols" do
it "converts header symbols from :content_type to 'Content-type'" do
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:content_type => 'abc')
headers.should have_key('Content-type')
headers['Content-type'].should == 'abc'
end
it "converts header symbols from :content_type to 'Content-type'" do
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:content_type => 'abc')
headers.should have_key('Content-type')
headers['Content-type'].should == 'abc'
end
it "converts content-type from extension to real content-type" do
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:content_type => 'json')
headers.should have_key('Content-type')
headers['Content-type'].should == 'application/json'
end
it "converts content-type from extension to real content-type" do
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:content_type => 'json')
headers.should have_key('Content-type')
headers['Content-type'].should == 'application/json'
end
it "converts accept from extension(s) to real content-type(s)" do
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:accept => 'json, mp3')
headers.should have_key('Accept')
headers['Accept'].should == 'application/json, audio/mpeg'
it "converts accept from extension(s) to real content-type(s)" do
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:accept => 'json, mp3')
headers.should have_key('Accept')
headers['Accept'].should == 'application/json, audio/mpeg'
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:accept => :json)
headers.should have_key('Accept')
headers['Accept'].should == 'application/json'
end
@request.should_receive(:default_headers).and_return({})
headers = @request.make_headers(:accept => :json)
headers.should have_key('Accept')
headers['Accept'].should == 'application/json'
end
it "converts header values to strings" do
@request.make_headers('A' => 1)['A'].should == '1'
it "converts header values to strings" do
@request.make_headers('A' => 1)['A'].should == '1'
end
end
it "executes by constructing the Net::HTTP object, headers, and payload and calling transmit" do
@ -153,35 +162,28 @@ describe RestClient::Request do
@request.transmit(@uri, 'req', 'payload')
end
it "uses SSL when the URI refers to a https address" do
@uri.stub!(:is_a?).with(URI::HTTPS).and_return(true)
@net.should_receive(:use_ssl=).with(true)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
describe "payload" do
it "sends nil payloads" do
@http.should_receive(:request).with('req', nil)
@request.should_receive(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', nil)
end
it "sends nil payloads" do
@http.should_receive(:request).with('req', nil)
@request.should_receive(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', nil)
end
it "passes non-hash payloads straight through" do
@request.process_payload("x").should == "x"
end
it "passes non-hash payloads straight through" do
@request.process_payload("x").should == "x"
end
it "converts a hash payload to urlencoded data" do
@request.process_payload(:a => 'b c+d').should == "a=b%20c%2Bd"
end
it "converts a hash payload to urlencoded data" do
@request.process_payload(:a => 'b c+d').should == "a=b%20c%2Bd"
end
it "accepts nested hashes in payload" do
payload = @request.process_payload(:user => { :name => 'joe', :location => { :country => 'USA', :state => 'CA' }})
payload.should include('user[name]=joe')
payload.should include('user[location][country]=USA')
payload.should include('user[location][state]=CA')
it "accepts nested hashes in payload" do
payload = @request.process_payload(:user => { :name => 'joe', :location => { :country => 'USA', :state => 'CA' }})
payload.should include('user[name]=joe')
payload.should include('user[location][country]=USA')
payload.should include('user[location][state]=CA')
end
end
it "set urlencoded content_type header on hash payloads" do
@ -189,31 +191,33 @@ describe RestClient::Request do
@request.headers[:content_type].should == 'application/x-www-form-urlencoded'
end
it "sets up the credentials prior to the request" do
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
describe "credentials" do
it "sets up the credentials prior to the request" do
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.stub!(:user).and_return('joe')
@request.stub!(:password).and_return('mypass')
@request.should_receive(:setup_credentials).with('req')
@request.stub!(:user).and_return('joe')
@request.stub!(:password).and_return('mypass')
@request.should_receive(:setup_credentials).with('req')
@request.transmit(@uri, 'req', nil)
end
@request.transmit(@uri, 'req', nil)
end
it "does not attempt to send any credentials if user is nil" do
@request.stub!(:user).and_return(nil)
req = mock("request")
req.should_not_receive(:basic_auth)
@request.setup_credentials(req)
end
it "does not attempt to send any credentials if user is nil" do
@request.stub!(:user).and_return(nil)
req = mock("request")
req.should_not_receive(:basic_auth)
@request.setup_credentials(req)
end
it "setup credentials when there's a user" do
@request.stub!(:user).and_return('joe')
@request.stub!(:password).and_return('mypass')
req = mock("request")
req.should_receive(:basic_auth).with('joe', 'mypass')
@request.setup_credentials(req)
it "setup credentials when there's a user" do
@request.stub!(:user).and_return('joe')
@request.stub!(:password).and_return('mypass')
req = mock("request")
req.should_receive(:basic_auth).with('joe', 'mypass')
@request.setup_credentials(req)
end
end
it "catches EOFError and shows the more informative ServerBrokeConnection" do
@ -233,111 +237,127 @@ describe RestClient::Request do
RestClient::Request.execute(1 => 2)
end
it "raises a Redirect with the new location when the response is in the 30x range" do
res = mock('response', :code => '301', :header => { 'Location' => 'http://new/resource'}, :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://new/resource'}
end
it "handles redirects with relative paths" do
res = mock('response', :code => '301', :header => { 'Location' => 'index' }, :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://some/index' }
end
it "handles redirects with absolute paths" do
@request.instance_variable_set('@url', 'http://some/place/else')
res = mock('response', :code => '301', :header => { 'Location' => '/index' }, :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://some/index' }
end
it "uses GET and clears payload and removes possible harmful headers when following 30x redirects" do
url = "http://example.com/redirected"
@request.should_receive(:execute_inner).once.ordered.and_raise(RestClient::Redirect.new(url))
@request.should_receive(:execute_inner).once.ordered do
@request.processed_headers.should_not have_key("Content-Length")
@request.url.should == url
@request.method.should == :get
@request.payload.should be_nil
describe "redirection" do
it "raises a Redirect with the new location when the response is in the 30x range" do
res = mock('response', :code => '301', :header => { 'Location' => 'http://new/resource'}, :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://new/resource'}
end
@request.execute
it "handles redirects with relative paths" do
res = mock('response', :code => '301', :header => { 'Location' => 'index' }, :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://some/index' }
end
it "handles redirects with absolute paths" do
@request.instance_variable_set('@url', 'http://some/place/else')
res = mock('response', :code => '301', :header => { 'Location' => '/index' }, :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Redirect) { |e| e.url.should == 'http://some/index' }
end
it "uses GET and clears payload and removes possible harmful headers when following 30x redirects" do
url = "http://example.com/redirected"
@request.should_receive(:execute_inner).once.ordered.and_raise(RestClient::Redirect.new(url))
@request.should_receive(:execute_inner).once.ordered do
@request.processed_headers.should_not have_key("Content-Length")
@request.url.should == url
@request.method.should == :get
@request.payload.should be_nil
end
@request.execute
end
end
it "raises Unauthorized when the response is 401" do
res = mock('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Unauthorized)
describe "exception" do
it "raises Unauthorized when the response is 401" do
res = mock('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::Unauthorized)
end
it "raises ResourceNotFound when the response is 404" do
res = mock('response', :code => '404', :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::ResourceNotFound)
end
it "raises RequestFailed otherwise" do
res = mock('response', :code => '500', :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::InternalServerError)
end
end
it "raises ResourceNotFound when the response is 404" do
res = mock('response', :code => '404', :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::ResourceNotFound)
describe "block usage" do
it "returns what asked to" do
res = mock('response', :code => '401', :[] => ['content-encoding' => ''], :body => '' )
@request.process_result(res){|response| "foo"}.should == "foo"
end
end
it "raises RequestFailed otherwise" do
res = mock('response', :code => '500', :[] => ['content-encoding' => ''], :body => '' )
lambda { @request.process_result(res) }.should raise_error(RestClient::InternalServerError)
describe "proxy" do
it "creates a proxy class if a proxy url is given" do
RestClient.stub!(:proxy).and_return("http://example.com/")
@request.net_http_class.should include(Net::HTTP::ProxyDelta)
end
it "creates a non-proxy class if a proxy url is not given" do
@request.net_http_class.should_not include(Net::HTTP::ProxyDelta)
end
end
it "creates a proxy class if a proxy url is given" do
RestClient.stub!(:proxy).and_return("http://example.com/")
@request.net_http_class.should include(Net::HTTP::ProxyDelta)
end
it "creates a non-proxy class if a proxy url is not given" do
@request.net_http_class.should_not include(Net::HTTP::ProxyDelta)
end
describe "logging" do
it "logs a get request" do
log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url').log_request
['RestClient.get "http://url", "Accept-encoding"=>"gzip, deflate", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.get "http://url", "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate"'].should include(log[0])
end
it "logs a get request" do
log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url').log_request
['RestClient.get "http://url", "Accept-encoding"=>"gzip, deflate", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.get "http://url", "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate"'].should include(log[0])
end
it "logs a post request with a small payload" do
log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').log_request
['RestClient.post "http://url", "foo", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.post "http://url", "foo", "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3"'].should include(log[0])
end
it "logs a post request with a small payload" do
log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => 'foo').log_request
['RestClient.post "http://url", "foo", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.post "http://url", "foo", "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"3"'].should include(log[0])
end
it "logs a post request with a large payload" do
log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).log_request
['RestClient.post "http://url", 1000 byte length, "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.post "http://url", 1000 byte length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000"'].should include(log[0])
end
it "logs a post request with a large payload" do
log = RestClient.log = []
RestClient::Request.new(:method => :post, :url => 'http://url', :payload => ('x' * 1000)).log_request
['RestClient.post "http://url", 1000 byte length, "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000", "Accept"=>"*/*; q=0.5, application/xml"',
'RestClient.post "http://url", 1000 byte length, "Accept"=>"*/*; q=0.5, application/xml", "Accept-encoding"=>"gzip, deflate", "Content-Length"=>"1000"'].should include(log[0])
end
it "logs input headers as a hash" do
log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' }).log_request
['RestClient.get "http://url", "Accept-encoding"=>"gzip, deflate", "Accept"=>"text/plain"',
'RestClient.get "http://url", "Accept"=>"text/plain", "Accept-encoding"=>"gzip, deflate"'].should include(log[0])
end
it "logs input headers as a hash" do
log = RestClient.log = []
RestClient::Request.new(:method => :get, :url => 'http://url', :headers => { :accept => 'text/plain' }).log_request
['RestClient.get "http://url", "Accept-encoding"=>"gzip, deflate", "Accept"=>"text/plain"',
'RestClient.get "http://url", "Accept"=>"text/plain", "Accept-encoding"=>"gzip, deflate"'].should include(log[0])
end
it "logs a response including the status code, content type, and result body size in bytes" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return('text/html')
@request.log_response res
log[0].should == "# => 200 OK | text/html 4 bytes"
end
it "logs a response including the status code, content type, and result body size in bytes" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return('text/html')
@request.log_response res
log[0].should == "# => 200 OK | text/html 4 bytes"
end
it "logs a response with a nil Content-type" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return(nil)
@request.log_response res
log[0].should == "# => 200 OK | 4 bytes"
end
it "logs a response with a nil Content-type" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => 'abcd')
res.stub!(:[]).with('Content-type').and_return(nil)
@request.log_response res
log[0].should == "# => 200 OK | 4 bytes"
end
it "logs a response with a nil body" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => nil)
res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8')
@request.log_response res
log[0].should == "# => 200 OK | text/html 0 bytes"
it "logs a response with a nil body" do
log = RestClient.log = []
res = mock('result', :code => '200', :class => Net::HTTPOK, :body => nil)
res.stub!(:[]).with('Content-type').and_return('text/html; charset=utf-8')
@request.log_response res
log[0].should == "# => 200 OK | text/html 0 bytes"
end
end
it "strips the charset from the response content type" do
@ -348,153 +368,166 @@ describe RestClient::Request do
log[0].should == "# => 200 OK | text/html 4 bytes"
end
it "set read_timeout" do
@request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
describe "timeout" do
it "set read_timeout" do
@request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :timeout => 123)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@net.should_receive(:read_timeout=).with(123)
@net.should_receive(:read_timeout=).with(123)
@request.transmit(@uri, 'req', nil)
@request.transmit(@uri, 'req', nil)
end
it "set open_timeout" do
@request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :open_timeout => 123)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@net.should_receive(:open_timeout=).with(123)
@request.transmit(@uri, 'req', nil)
end
end
it "set open_timeout" do
@request = RestClient::Request.new(:method => :put, :url => 'http://some/resource', :payload => 'payload', :open_timeout => 123)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
describe "ssl" do
it "uses SSL when the URI refers to a https address" do
@uri.stub!(:is_a?).with(URI::HTTPS).and_return(true)
@net.should_receive(:use_ssl=).with(true)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
@net.should_receive(:open_timeout=).with(123)
it "should default to not verifying ssl certificates" do
@request.verify_ssl.should == false
end
@request.transmit(@uri, 'req', nil)
end
it "should set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is false" do
@net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not verifying ssl certificates" do
@request.verify_ssl.should == false
end
it "should not set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is true" do
@request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
@net.should_not_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is false" do
@net.should_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set net.verify_mode to the passed value if verify_ssl is an OpenSSL constant" do
mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
@request = RestClient::Request.new( :method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:verify_ssl => mode )
@net.should_receive(:verify_mode=).with(mode)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should not set net.verify_mode to OpenSSL::SSL::VERIFY_NONE if verify_ssl is true" do
@request = RestClient::Request.new(:method => :put, :url => 'https://some/resource', :payload => 'payload', :verify_ssl => true)
@net.should_not_receive(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not having an ssl_client_cert" do
@request.ssl_client_cert.should be(nil)
end
it "should set net.verify_mode to the passed value if verify_ssl is an OpenSSL constant" do
mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
@request = RestClient::Request.new( :method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:verify_ssl => mode )
@net.should_receive(:verify_mode=).with(mode)
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set the ssl_client_cert if provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_client_cert => "whatsupdoc!"
)
@net.should_receive(:cert=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not having an ssl_client_cert" do
@request.ssl_client_cert.should be(nil)
end
it "should not set the ssl_client_cert if it is not provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload'
)
@net.should_not_receive(:cert=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set the ssl_client_cert if provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_client_cert => "whatsupdoc!"
)
@net.should_receive(:cert=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not having an ssl_client_key" do
@request.ssl_client_key.should be(nil)
end
it "should not set the ssl_client_cert if it is not provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload'
)
@net.should_not_receive(:cert=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set the ssl_client_key if provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_client_key => "whatsupdoc!"
)
@net.should_receive(:key=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not having an ssl_client_key" do
@request.ssl_client_key.should be(nil)
end
it "should not set the ssl_client_key if it is not provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload'
)
@net.should_not_receive(:key=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set the ssl_client_key if provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_client_key => "whatsupdoc!"
)
@net.should_receive(:key=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not having an ssl_ca_file" do
@request.ssl_ca_file.should be(nil)
end
it "should not set the ssl_client_key if it is not provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload'
)
@net.should_not_receive(:key=).with("whatsupdoc!")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should set the ssl_ca_file if provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_ca_file => "Certificate Authority File"
)
@net.should_receive(:ca_file=).with("Certificate Authority File")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should default to not having an ssl_ca_file" do
@request.ssl_ca_file.should be(nil)
end
it "should set the ssl_ca_file if provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload',
:ssl_ca_file => "Certificate Authority File"
)
@net.should_receive(:ca_file=).with("Certificate Authority File")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
it "should not set the ssl_ca_file if it is not provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload'
)
@net.should_not_receive(:ca_file=).with("Certificate Authority File")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
it "should not set the ssl_ca_file if it is not provided" do
@request = RestClient::Request.new(
:method => :put,
:url => 'https://some/resource',
:payload => 'payload'
)
@net.should_not_receive(:ca_file=).with("Certificate Authority File")
@http.stub!(:request)
@request.stub!(:process_result)
@request.stub!(:response_log)
@request.transmit(@uri, 'req', 'payload')
end
end
it "should still return a response object for 204 No Content responses" do

View file

@ -18,13 +18,13 @@ describe RestClient::Response do
@response.raw_headers["Status"][0].should == "200 OK"
@response.headers[:status].should == "200 OK"
end
describe "cookie processing" do
it "should correctly deal with one Set-Cookie header with one cookie inside" do
net_http_res = mock('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT"]})
response = RestClient::Response.new('abc', net_http_res)
response.headers[:set_cookie].should == ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT"]
response.cookies.should == { "main_page" => "main_page_no_rewrite" }
response.cookies.should == { "main_page" => "main_page_no_rewrite" }
end
it "should correctly deal with multiple cookies [multiple Set-Cookie headers]" do
@ -32,9 +32,9 @@ describe RestClient::Response do
response = RestClient::Response.new('abc', net_http_res)
response.headers[:set_cookie].should == ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT", "remember_me=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT", "user=somebody; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"]
response.cookies.should == {
"main_page" => "main_page_no_rewrite",
"remember_me" => "",
"user" => "somebody"
"main_page" => "main_page_no_rewrite",
"remember_me" => "",
"user" => "somebody"
}
end
@ -42,11 +42,31 @@ describe RestClient::Response do
net_http_res = mock('net http response', :to_hash => {"etag" => ["\"e1ac1a2df945942ef4cac8116366baad\""], "set-cookie" => ["main_page=main_page_no_rewrite; path=/; expires=Tue, 20-Jan-2015 15:03:14 GMT, remember_me=; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT, user=somebody; path=/; expires=Thu, 01-Jan-1970 00:00:00 GMT"]})
response = RestClient::Response.new('abc', net_http_res)
response.cookies.should == {
"main_page" => "main_page_no_rewrite",
"remember_me" => "",
"user" => "somebody"
"main_page" => "main_page_no_rewrite",
"remember_me" => "",
"user" => "somebody"
}
end
end
describe "exceptions processing" do
it "should return itself for normal codes" do
(200..206).each do |code|
net_http_res = mock('net http response', :code => '200')
response = RestClient::Response.new('abc', net_http_res)
response.return!
end
end
it "should throw an exception for other codes" do
RestClient::Exceptions::EXCEPTIONS_MAP.each_key do |code|
net_http_res = mock('net http response', :code => code.to_i)
response = RestClient::Response.new('abc', net_http_res)
lambda { response.return!}.should raise_error
end
end
end
end