Permalink
Browse files

Refactor redirects

  • Loading branch information...
1 parent a3e536c commit bb29bd1f1f5c7c3eb7883591d206a7f2aadcec2e Paul Sadauskas committed May 13, 2008
View
@@ -1,4 +1,3 @@
#!/usr/bin/env ruby
require 'autotest/redgreen'
-require 'autotest/timestamp'
View
@@ -1,5 +1,7 @@
require 'resourceful/http_accessor'
+require 'resourceful/util'
+
# Resourceful is a library that provides a high level HTTP interface.
module Resourceful
# A Hash of named URIs. Many methods in Resourceful that need a URI
@@ -5,19 +5,31 @@ module Resourceful
class Request
+ REDIRECTABLE_METHODS = [:get, :head]
+
attr_accessor :method, :resource, :body, :header
def initialize(http_method, resource, body = nil, header = nil)
@method, @resource, @body, @header = http_method, resource, body, header
+ @response = nil
end
- def make
-
- http_resp = NetHttpAdapter.make_request(@method, @resource.uri, @body, @header)
- response = Resourceful::Response.new(*http_resp)
+ def response
+ if @response.nil?
+ http_resp = NetHttpAdapter.make_request(@method, @resource.uri, @body, @header)
+ @response = Resourceful::Response.new(*http_resp)
+ end
- response
+ @response
+ end
+ def should_be_redirected?
+ if resource.on_redirect.nil?
+ return true if method.in? REDIRECTABLE_METHODS
+ false
+ else
+ resource.on_redirect.call(self, response)
+ end
end
end
@@ -24,29 +24,26 @@ def on_redirect(&block)
end
def get
- request = Resourceful::Request.new(:get, self)
- response = request.make
-
- if response.code == 301
- if @on_redirect.nil? or @on_redirect.call(request, response)
- @uris.unshift response.header['Location'].first
- request = Resourceful::Request.new(:get, self)
- response = request.make
- end
- end
-
- response
+ do_read_request(:get)
end
def post(data = "")
request = Resourceful::Request.new(:post, self, data)
- response = request.make
+ response = request.response
if response.code == 301
if @on_redirect and @on_redirect.call(request, response)
@uris.unshift response.header['Location'].first
request = Resourceful::Request.new(:post, self)
- response = request.make
+ response = request.response
+ end
+ end
+ if response.code == 302
+ if @on_redirect and @on_redirect.call(request, response)
+ @uris.unshift response.header['Location'].first
+ request = Resourceful::Request.new(:get, self)
+ response = request.response
+ @uris.shift # don't remember this new location
end
end
@@ -55,13 +52,21 @@ def post(data = "")
def put(data = "")
request = Resourceful::Request.new(:put, self, data)
- response = request.make
+ response = request.response
if response.code == 301
if @on_redirect and @on_redirect.call(request, response)
@uris.unshift response.header['Location'].first
request = Resourceful::Request.new(:put, self)
- response = request.make
+ response = request.response
+ end
+ end
+ if response.code == 302
+ if @on_redirect and @on_redirect.call(request, response)
+ @uris.unshift response.header['Location'].first
+ request = Resourceful::Request.new(:get, self)
+ response = request.response
+ @uris.shift # don't remember this new location
end
end
@@ -70,19 +75,49 @@ def put(data = "")
def delete
request = Resourceful::Request.new(:delete, self)
- response = request.make
+ response = request.response
if response.code == 301
if @on_redirect and @on_redirect.call(request, response)
@uris.unshift response.header['Location'].first
request = Resourceful::Request.new(:delete, self)
- response = request.make
+ response = request.response
+ end
+ end
+ if response.code == 302
+ if @on_redirect and @on_redirect.call(request, response)
+ @uris.unshift response.header['Location'].first
+ request = Resourceful::Request.new(:get, self)
+ response = request.response
+ @uris.shift # don't remember this new location
end
end
response
end
+ protected
+
+ def do_read_request(method)
+ request = Resourceful::Request.new(:get, self)
+ response = request.response
+
+ if response.is_redirect? and request.should_be_redirected?
+ previous_response = response
+ @uris.unshift response.header['Location'].first
+ request = Resourceful::Request.new(:delete, self)
+ response = request.response
+ @uris.shift unless previous_response.code == 301
+ end
+
+ response
+
+ end
+
+ def do_write_request(method, data)
+
+ end
+
end
end
@@ -3,13 +3,20 @@
module Resourceful
class Response
+ REDIRECT_RESPONSE_CODES = [301,302,303,307]
+
attr_reader :code, :header, :body
alias headers header
def initialize(code, header, body)
@code, @header, @body = code, header, body
end
+ def is_redirect?
+ @code.in? REDIRECT_RESPONSE_CODES
+ end
+ alias was_redirect? is_redirect?
+
end
end
@@ -0,0 +1,6 @@
+
+class Object
+ def in?(arr)
+ arr.include?(self)
+ end
+end
@@ -0,0 +1,36 @@
+describe 'redirect', :shared => true do
+ before do
+ @callback = mock('callback')
+ @callback.stub!(:call).and_return(true)
+ end
+
+ it 'should be followed by default on GET' do
+ resp = @resource.get
+ resp.should be_instance_of(Resourceful::Response)
+ resp.code.should == 200
+ resp.header['Content-Type'].should == ['text/plain']
+ end
+
+ %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
+ end
+
+ it "should redirect on #{method} if the redirection callback returns true" do
+ @resource.on_redirect { @callback.call }
+ resp = @resource.send(method.downcase.intern)
+ resp.code.should == 200
+ end
+
+ it "should not redirect on #{method} if the redirection callback returns false" do
+ @callback.stub!(:call).and_return(false)
+ @resource.on_redirect { @callback.call }
+ resp = @resource.send(method.downcase.intern)
+ resp.code.should == @redirect_code
+ end
+ end
+
+end
+
@@ -1,5 +1,6 @@
require 'pathname'
require Pathname(__FILE__).dirname + 'spec_helper'
+require Pathname(__FILE__).dirname + 'acceptance_shared_specs'
require 'resourceful'
@@ -51,7 +52,7 @@
resp.header['Content-Type'].should == ['text/plain']
end
- describe 'redirects' do
+ describe 'redirecting' do
describe 'registering callback' do
before do
@@ -81,39 +82,11 @@
describe '301 Moved Permanently' do
before do
+ @redirect_code = 301
@resource = @accessor.resource('http://localhost:3000/redirect/301?http://localhost:3000/get')
-
- @callback = mock('callback')
- @callback.stub!(:call).and_return(true)
end
- it 'should be followed by default on GET' do
- resp = @resource.get
- resp.should be_instance_of(Resourceful::Response)
- resp.code.should == 200
- resp.header['Content-Type'].should == ['text/plain']
- end
-
- %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 == 301
- end
-
- it "should redirect on #{method} if the redirection callback returns true" do
- @resource.on_redirect { @callback.call }
- resp = @resource.send(method.downcase.intern)
- resp.code.should == 200
- end
-
- it "should not redirect on #{method} if the redirection callback returns false" do
- @callback.stub!(:call).and_return(false)
- @resource.on_redirect { @callback.call }
- resp = @resource.send(method.downcase.intern)
- resp.code.should == 301
- end
- end
+ it_should_behave_like 'redirect'
it 'should change the effective uri of the resource' do
@resource.get
@@ -123,9 +96,26 @@
end
describe '302 Found' do
+ before do
+ @redirect_code = 302
+ @resource = @accessor.resource('http://localhost:3000/redirect/302?http://localhost:3000/get')
+ end
+
+ it_should_behave_like 'redirect'
+
+ it 'should not change the effective uri of the resource'
+
+ end
+
+ describe '303 Other' do
+
+ end
+
+ describe '307 Temporary Redirect' do
end
+
end
describe 'caching' do
@@ -144,6 +134,18 @@
it 'should raise InvalidResponse when response code is invalid'
+ describe 'client errors' do
+
+ it 'should raise when there is one'
+
+ end
+
+ describe 'server errors' do
+
+ it 'should raise when there is one'
+
+ end
+
end
end
Oops, something went wrong.

0 comments on commit bb29bd1

Please sign in to comment.