Skip to content

Commit

Permalink
merge pezra/master
Browse files Browse the repository at this point in the history
  • Loading branch information
Paul Sadauskas committed Jun 23, 2008
2 parents 69ce0fe + 7216229 commit 455715a
Show file tree
Hide file tree
Showing 14 changed files with 255 additions and 40 deletions.
11 changes: 8 additions & 3 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
rdoc.rdoc_files.include('lib/**/*.rb')
end

desc 'Removes all temporary files'
task :clean

##############################################################################
# Packaging & Installation
##############################################################################

RESOURCEFUL_VERSION = "0.1"
RESOURCEFUL_VERSION = "0.2"

windows = (PLATFORM =~ /win32|cygwin/) rescue nil

Expand All @@ -47,17 +50,19 @@ spec = Gem::Specification.new do |s|
s.summary = "Resourceful provides a convenient Ruby API for making HTTP requests."
s.description = s.summary
s.require_path = "lib"
s.files = %w( LICENSE README Rakefile ) + Dir["{docs,spec,lib}/**/*"]
s.files = %w( MIT-LICENSE README Rakefile ) + Dir["{docs,spec,lib}/**/*"]

# rdoc
s.has_rdoc = true
s.extra_rdoc_files = %w( README LICENSE )
s.extra_rdoc_files = %w( README MIT-LICENSE )

# Dependencies
s.add_dependency "addressable"
s.add_dependency "httpauth"
s.add_dependency "rspec"
s.add_dependency "tiny"
s.add_dependency "facets"

s.required_ruby_version = ">= 1.8.6"
end

Expand Down
12 changes: 5 additions & 7 deletions lib/resourceful/authentication_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,11 @@ def initialize(realm, username, password)
end

def valid_for?(challenge_response)
return false unless challenge = challenge_response.header['WWW-Authenticate']
begin
realm = HTTPAuth::Basic.unpack_challenge(challenge.first)
rescue ArgumentError
return false
end
realm == @realm
return false unless challenge_response.header['WWW-Authenticate']

!challenge_response.header['WWW-Authenticate'].grep(/^\s*basic/i).find do |a_challenge|
@realm.downcase == /realm="([^"]+)"/i.match(a_challenge)[1].downcase
end.nil?
end

def update_credentials(challenge)
Expand Down
13 changes: 10 additions & 3 deletions lib/resourceful/net_http_adapter.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'net/http'
require 'net/https'
require 'addressable/uri'

require 'resourceful/header'
Expand All @@ -21,15 +22,21 @@ def self.make_request(method, uri, body = nil, header = nil)

req = net_http_request_class(method).new(uri.absolute_path)
header.each { |k,v| req[k] = v } if header
res = Net::HTTP.start(uri.host, uri.port) do |conn|
conn.request(req, body)
conn = Net::HTTP.new(uri.host, uri.port)
conn.use_ssl = (/https/i === uri.scheme)
begin
conn.start
res = conn.request(req, body)
ensure
conn.finish
end

[ Integer(res.code),
Resourceful::Header.new(res.header.to_hash),
res.body
]

ensure

end

private
Expand Down
1 change: 1 addition & 0 deletions lib/resourceful/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def initialize(http_method, resource, body = nil, header = nil)
@method, @resource, @body = http_method, resource, body
@header = header.is_a?(Resourceful::Header) ? header : Resourceful::Header.new(header || {})

@header['Accept-Encoding'] = 'gzip, identity'
end

def response
Expand Down
21 changes: 21 additions & 0 deletions lib/resourceful/resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

module Resourceful

# This exception used to indicate that the request did not succeed.
# The HTTP response is included so that the appropriate actions can
# be taken based on the details of that response
class UnsuccessfulHttpRequestError < Exception
attr_reader :http_response, :http_request

# Initialize new error from the HTTP request and response attributes.
#--
# @private
def initialize(http_request, http_response)
super("#{http_request.method} request to <#{http_request.uri}> failed with code #{http_response.code}")
@http_request = http_request
@http_response = http_response
end
end

class Resource
attr_reader :accessor

Expand Down Expand Up @@ -119,6 +135,8 @@ def do_read_request(method)
response = do_read_request(method)
end

raise UnsuccessfulHttpRequestError.new(request,response) unless response.is_success?

return response
end

Expand All @@ -134,6 +152,8 @@ def do_read_request(method)
# @private
def do_write_request(method, data = nil)
request = Resourceful::Request.new(method, self, data)
accessor.auth_manager.add_credentials(request)

response = request.response

if response.is_redirect? and request.should_be_redirected?
Expand All @@ -149,6 +169,7 @@ def do_write_request(method, data = nil)
end
end

raise UnsuccessfulHttpRequestError.new(request,response) unless response.is_success?
return response
end

Expand Down
28 changes: 28 additions & 0 deletions lib/resourceful/response.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
require 'net/http'
require 'time'
require 'facets/kernel/ergo'

module Resourceful
# Exception indicating that the server used a content coding scheme
# that Resourceful is unable to handle.
class UnsupportedContentCoding < Exception
end

class Response
REDIRECT_RESPONSE_CODES = [301,302,303,307]
Expand All @@ -17,6 +22,10 @@ def initialize(uri, code, header, body)
@response_time = Time.now
end

def is_success?
@code.in? 200..299
end

def is_redirect?
@code.in? REDIRECT_RESPONSE_CODES
end
Expand Down Expand Up @@ -69,6 +78,25 @@ def current_age
corrected_received_age = [apparent_age, age_value || 0].max
current_age = corrected_received_age + (response_time - request_time) + (now - response_time)
end

def body
case header['Content-Encoding'].ergo.first
when nil
# body is identity encoded; just return it
@body
when /^\s*identity\s*$/i
# body is identity encoded; just return it
@body
when /^\s*gzip\s*$/i
gz_in = Zlib::GzipReader.new(StringIO.new(@body, 'r'))
@body = gz_in.read
gz_in.close
header.delete('Content-Encoding')
@body
else
raise UnsupportedContentCoding, "Resourceful does not support #{header['Content-Encoding'].ergo.first} content coding"
end
end
end

end
11 changes: 6 additions & 5 deletions spec/acceptance_shared_specs.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

%w{PUT POST DELETE}.each do |method|
it "should not be followed by default on #{method}" do
resp = @resource.send(method.downcase.intern)
resp.should be_instance_of(Resourceful::Response)
resp.code.should == @redirect_code
lambda {
@resource.send(method.downcase.intern)
}.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
end

it "should redirect on #{method} if the redirection callback returns true" do
Expand All @@ -21,8 +21,9 @@

it "should not redirect on #{method} if the redirection callback returns false" do
@resource.on_redirect { false }
resp = @resource.send(method.downcase.intern)
resp.code.should == @redirect_code
lambda {
@resource.send(method.downcase.intern)
}.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
end
end

Expand Down
12 changes: 7 additions & 5 deletions spec/acceptance_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@

it 'should not perform the redirect if the callback returns false' do
@callback.should_receive(:call).and_return(false)
resp = @resource.get
resp.code.should == 301
lambda {
@resource.get
}.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
end
end

Expand Down Expand Up @@ -291,9 +292,10 @@
basic_handler = Resourceful::BasicAuthenticator.new('Test Auth', 'admin', 'well-known')
@accessor.auth_manager.add_auth_handler(basic_handler)
resource = @accessor.resource(@uri)
resp = resource.get

resp.code.should == 401
lambda {
resource.get
}.should raise_error(Resourceful::UnsuccessfulHttpRequestError)
end

end
Expand All @@ -303,7 +305,7 @@
@uri = 'http://localhost:3000/auth/digest'
end

it 'should be able to authenticate basic auth' do
it 'should be able to authenticate digest auth' do
pending
digest_handler = Resourceful::DigestAuthenticator.new('Test Auth', 'admin', 'secret')
@accessor.auth_manager.add_auth_handler(digest_handler)
Expand Down
27 changes: 24 additions & 3 deletions spec/resourceful/authentication_manager_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,42 @@

describe "Updating from a challenge response" do
before do
@header = {'WWW-Authenticate' => 'Basic realm="Test Auth"'}
@header = {'WWW-Authenticate' => ['Basic realm="Test Auth"']}
@chal = mock('response', :header => @header, :uri => 'http://example.com/foo/bar')
end

it 'should be valid for a challenge response with scheme "Basic" and the same realm' do
@auth.valid_for?(@chal).should be_true
end

it 'should be valid for a challenge response with multiple schemes including matchin "Basic" challenge' do
@header = {'WWW-Authenticate' => ['Digest some other stuff', 'Basic realm="Test Auth"', 'Weird scheme']}

@auth.valid_for?(@chal).should be_true
end

it 'should not be sensitive to case variances in the scheme' do
@header['WWW-Authenticate'] = ['bAsIc realm="Test Auth"']
@auth.valid_for?(@chal).should be_true
end

it 'should not be sensitive to case variances in the realm directive' do
@header['WWW-Authenticate'] = ['Basic rEaLm="Test Auth"']
@auth.valid_for?(@chal).should be_true
end

it 'should not be sensitive to case variances in the realm value' do
@header['WWW-Authenticate'] = ['Basic realm="test auth"']
@auth.valid_for?(@chal).should be_true
end

it 'should not be valid if the scheme is not "Basic"' do
@header['WWW-Authenticate'] = "Digest"
@header['WWW-Authenticate'] = ["Digest"]
@auth.valid_for?(@chal).should be_false
end

it 'should not be valid if the realm does not match' do
@header['WWW-Authenticate'] = 'Basic realm="not test auth"'
@header['WWW-Authenticate'] = ['Basic realm="not test auth"']
@auth.valid_for?(@chal).should be_false
end

Expand Down
17 changes: 16 additions & 1 deletion spec/resourceful/net_http_adapter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,29 @@

require 'resourceful/net_http_adapter'

describe Resourceful::NetHttpAdapter do
describe '#make_request (mocked)' do
it 'should enable ssl on the connection' do
resp = stub('http_response', :code => 200, :header => {}, :body => "hello")
conn = stub('http_conn', :request => resp, :finish => nil)
Net::HTTP.should_receive(:new).and_return(conn)
conn.should_receive(:use_ssl=).with(true).ordered
conn.should_receive(:start).ordered

Resourceful::NetHttpAdapter.make_request(:get, 'https://localhost:3000/get')
end
end
end

describe Resourceful::NetHttpAdapter do
it_should_behave_like 'simple http server'


describe '#make_request' do
before do
@response = Resourceful::NetHttpAdapter.make_request(:get, 'http://localhost:3000/get')
end

describe 'response' do
it 'should be an array' do
@response.should be_instance_of(Array)
Expand Down
7 changes: 6 additions & 1 deletion spec/resourceful/request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,13 @@
request.should_be_redirected?.should be_false
end

end # #should_be_redirected?
end

describe "content coding" do
it "should set Accept-Encoding automatically" do
@request.header['Accept-Encoding'].should == 'gzip'
end
end

end

Loading

0 comments on commit 455715a

Please sign in to comment.