Don't follow external redirects

This commit is contained in:
Josh Knowles 2009-01-04 23:56:52 -05:00
parent 4565a3cea6
commit 9825aee47e
11 changed files with 116 additions and 29 deletions

View File

@ -110,7 +110,7 @@ For example:
@http_method = http_method @http_method = http_method
@data = data @data = data
request_page(response.headers["Location"], :get, data) if redirect? request_page(response_location, :get, data) if internal_redirect?
return response return response
end end
@ -118,11 +118,15 @@ For example:
def success_code? #:nodoc: def success_code? #:nodoc:
(200..499).include?(response_code) (200..499).include?(response_code)
end end
def redirect? #:nodoc: def redirect? #:nodoc:
response_code / 100 == 3 response_code / 100 == 3
end end
def internal_redirect? #:nodoc:
redirect? && current_host == response_location_host
end
def exception_caught? #:nodoc: def exception_caught? #:nodoc:
response_body =~ /Exception caught/ response_body =~ /Exception caught/
end end
@ -222,6 +226,18 @@ For example:
private private
def response_location
response.headers["Location"]
end
def current_host
URI.parse(current_url).host || "www.example.com"
end
def response_location_host
URI.parse(response_location).host || "www.example.com"
end
def reset def reset
@elements = {} @elements = {}
@_scopes = nil @_scopes = nil

View File

@ -7,8 +7,12 @@ class Testing < Application
def submit_form def submit_form
end end
def redirect_to_root def internal_redirect
redirect "/" redirect "/"
end end
def external_redirect
redirect "http://google.com"
end
end end

View File

@ -28,5 +28,6 @@
Merb.logger.info("Compiling routes...") Merb.logger.info("Compiling routes...")
Merb::Router.prepare do Merb::Router.prepare do
match("/").to(:controller => "testing", :action => "show_form") match("/").to(:controller => "testing", :action => "show_form")
match("/redirect").to(:controller => "testing", :action => "redirect_to_root") match("/internal_redirect").to(:controller => "testing", :action => "internal_redirect")
match("/external_redirect").to(:controller => "testing", :action => "external_redirect")
end end

View File

@ -14,8 +14,14 @@ describe "Webrat" do
click_button "Test" click_button "Test"
end end
it "should follow redirects" do it "should follow internal redirects" do
response = visit "/redirect" response = visit "/internal_redirect"
response.status.should == 200
response.should contain("Webrat Form") response.should contain("Webrat Form")
end end
it "should not follow external redirects" do
response = visit "/external_redirect"
response.status.should == 302
end
end end

View File

@ -7,8 +7,12 @@ class WebratController < ApplicationController
render :text => "OK" render :text => "OK"
end end
def redirect def internal_redirect
redirect_to :submit redirect_to :submit
end end
def external_redirect
redirect_to "http://google.com"
end
end end

View File

@ -1,7 +1,8 @@
ActionController::Routing::Routes.draw do |map| ActionController::Routing::Routes.draw do |map|
map.with_options :controller => "webrat" do |webrat| map.with_options :controller => "webrat" do |webrat|
webrat.submit "/submit", :action => "submit" webrat.submit "/submit", :action => "submit"
webrat.redirect "/redirect", :action => "redirect" webrat.internal_redirect "/internal_redirect", :action => "internal_redirect"
webrat.external_redirect "/external_redirect", :action => "external_redirect"
webrat.root :action => "form" webrat.root :action => "form"
end end

View File

@ -15,8 +15,13 @@ class WebratTest < ActionController::IntegrationTest
click_button "Test" click_button "Test"
end end
test "should follow redirects" do test "should follow internal redirects" do
visit redirect_path visit internal_redirect_path
assert response.body.include?("OK") assert response.body.include?("OK")
end end
test "should not follow external redirects" do
visit external_redirect_path
assert response.redirect?
end
end end

View File

@ -1,26 +1,30 @@
require "rubygems" require "rubygems"
require "sinatra" require "sinatra"
use_in_file_templates! use_in_file_templates!
get "/" do get "/" do
erb :home erb :home
end end
get "/go" do get "/go" do
erb :go erb :go
end end
get "/redirect" do get "/internal_redirect" do
redirect "/" redirect "/"
end end
get "/external_redirect" do
redirect "http://google.com"
end
post "/go" do post "/go" do
@user = params[:name] @user = params[:name]
@email = params[:email] @email = params[:email]
erb :hello erb :hello
end end
__END__ __END__
@@ layout @@ layout
@ -31,10 +35,10 @@ __END__
<%= yield %> <%= yield %>
</body> </body>
</html> </html>
@@ home @@ home
<p> visit <a href="/go">there</a></p> <p> visit <a href="/go">there</a></p>
@@ go @@ go
<form method="post" action="/go"> <form method="post" action="/go">
<div> <div>
@ -47,7 +51,7 @@ __END__
</div> </div>
<input type="submit" value="Submit" /> <input type="submit" value="Submit" />
</form> </form>
@@ hello @@ hello
<p>Hello, <%= @user %></p> <p>Hello, <%= @user %></p>
<p>Your email is: <%= @email %></p> <p>Your email is: <%= @email %></p>

View File

@ -8,19 +8,24 @@ class WebratTest < Test::Unit::TestCase
click_link "there" click_link "there"
assert response_body.include?('<form method="post" action="/go">') assert response_body.include?('<form method="post" action="/go">')
end end
def test_submits_form def test_submits_form
visit "/go" visit "/go"
fill_in "Name", :with => "World" fill_in "Name", :with => "World"
fill_in "Email", :with => "world@example.org" fill_in "Email", :with => "world@example.org"
click_button "Submit" click_button "Submit"
assert response_body.include?("Hello, World") assert response_body.include?("Hello, World")
assert response_body.include?("Your email is: world@example.org") assert response_body.include?("Your email is: world@example.org")
end end
def test_follows_redirects def test_follows_internal_redirects
visit "/redirect" visit "/internal_redirect"
assert response_body.include?("visit") assert response_body.include?("visit")
end end
def test_does_not_follow_external_redirects
visit "/external_redirect"
assert response_code == 302
end
end end

View File

@ -113,14 +113,22 @@ describe Webrat::Session do
lambda { webrat_session.request_page('some url', :get, {}) }.should raise_error(Webrat::PageLoadError) lambda { webrat_session.request_page('some url', :get, {}) }.should raise_error(Webrat::PageLoadError)
end end
it "should follow redirects" do it "should follow internal redirects" do
webrat_session.should_receive(:redirect?).twice.and_return(true, false) webrat_session.should_receive(:internal_redirect?).twice.and_return(true, false)
webrat_session.response.should_receive(:headers).once.and_return({ "Location" => "/newurl" }) webrat_session.response.should_receive(:headers).once.and_return({ "Location" => "/newurl" })
webrat_session.request_page("/oldurl", :get, {}) webrat_session.request_page("/oldurl", :get, {})
webrat_session.current_url.should == "/newurl" webrat_session.current_url.should == "/newurl"
end end
it "should now follow external redirects" do
webrat_session.should_receive(:internal_redirect?).and_return(false)
webrat_session.request_page("/oldurl", :get, {})
webrat_session.current_url.should == "/oldurl"
end
end end
describe "#redirect?" do describe "#redirect?" do
@ -138,4 +146,29 @@ describe Webrat::Session do
webrat_session.redirect?.should be_false webrat_session.redirect?.should be_false
end end
end end
describe "#internal_redirect?" do
before(:each) do
webrat_session = Webrat::Session.new
end
it "should return true if the last response was a redirect and the host of the current_url matches that of the response location" do
webrat_session.stub!(:redirect? => true)
webrat_session.stub!(:current_url => "http://example.com")
webrat_session.stub!(:response_location => "http://example.com")
webrat_session.internal_redirect?.should be_true
end
it "should return false if the last response was not a redirect" do
webrat_session.stub!(:redirect? => false)
webrat_session.internal_redirect?.should be_false
end
it "should return false if the last response was a redirect but the host of the current_url doesn't matches that of the response location" do
webrat_session.stub!(:redirect? => true)
webrat_session.stub!(:current_url => "http://example.com")
webrat_session.stub!(:response_location => "http://google.com")
webrat_session.internal_redirect?.should be_false
end
end
end end

View File

@ -31,14 +31,22 @@ describe "visit" do
lambda { fill_in "foo", :with => "blah" }.should raise_error(Webrat::WebratError) lambda { fill_in "foo", :with => "blah" }.should raise_error(Webrat::WebratError)
end end
it "should follow redirects" do it "should follow internal redirects" do
webrat_session.should_receive(:redirect?).twice.and_return(true, false) webrat_session.should_receive(:internal_redirect?).twice.and_return(true, false)
webrat_session.response.should_receive(:headers).once.and_return({ "Location" => "/newurl" }) webrat_session.response.should_receive(:headers).once.and_return({ "Location" => "/newurl" })
visit("/oldurl") visit("/oldurl")
current_url.should == "/newurl" current_url.should == "/newurl"
end end
it "should not follow external redirects" do
webrat_session.should_receive(:internal_redirect?).and_return(false)
visit("/oldurl")
current_url.should == "/oldurl"
end
end end
describe "visit with referer" do describe "visit with referer" do