Forward headers during redirects when using the RailsSession.

This commit is contained in:
Josh Knowles 2008-12-25 16:53:06 -05:00
parent bd6f4986fb
commit b88b2b2949
4 changed files with 175 additions and 106 deletions

View File

@ -7,51 +7,53 @@ module Webrat
def doc_root def doc_root
File.expand_path(File.join(RAILS_ROOT, 'public')) File.expand_path(File.join(RAILS_ROOT, 'public'))
end end
def saved_page_dir def saved_page_dir
File.expand_path(File.join(RAILS_ROOT, "tmp")) File.expand_path(File.join(RAILS_ROOT, "tmp"))
end end
def get(url, data, headers = nil) def get(url, data, headers = nil)
do_request(:get, url, data, headers) do_request(:get, url, data, headers)
end end
def post(url, data, headers = nil) def post(url, data, headers = nil)
do_request(:post, url, data, headers) do_request(:post, url, data, headers)
end end
def put(url, data, headers = nil) def put(url, data, headers = nil)
do_request(:put, url, data, headers) do_request(:put, url, data, headers)
end end
def delete(url, data, headers = nil) def delete(url, data, headers = nil)
do_request(:delete, url, data, headers) do_request(:delete, url, data, headers)
end end
def response_body def response_body
response.body response.body
end end
def response_code def response_code
response.code.to_i response.code.to_i
end end
def xml_content_type? def xml_content_type?
response.headers["Content-Type"].to_s =~ /xml/ response.headers["Content-Type"].to_s =~ /xml/
end end
protected protected
def integration_session def integration_session
@context @context
end end
def do_request(http_method, url, data, headers) #:nodoc: def do_request(http_method, url, data, headers) #:nodoc:
update_protocol(url) update_protocol(url)
url = normalize_url(url)
integration_session.request_via_redirect(http_method, url, data, headers) integration_session.send(http_method, normalize_url(url), data, headers)
integration_session.follow_redirect_with_headers(headers) while integration_session.internal_redirect?
integration_session.status
end end
# remove protocol, host and anchor # remove protocol, host and anchor
def normalize_url(href) #:nodoc: def normalize_url(href) #:nodoc:
uri = URI.parse(href) uri = URI.parse(href)
@ -61,7 +63,7 @@ module Webrat
end end
normalized_url normalized_url
end end
def update_protocol(href) #:nodoc: def update_protocol(href) #:nodoc:
if href =~ /^https:/ if href =~ /^https:/
integration_session.https!(true) integration_session.https!(true)
@ -69,24 +71,31 @@ module Webrat
integration_session.https!(false) integration_session.https!(false)
end end
end end
def response #:nodoc: def response #:nodoc:
integration_session.response integration_session.response
end end
end end
end end
module ActionController #:nodoc: module ActionController #:nodoc:
module Integration #:nodoc: module Integration #:nodoc:
Session.class_eval do class Session #:nodoc:
unless instance_methods.include?("put_via_redirect") def internal_redirect?
require "webrat/rails/redirect_actions" redirect? && response.redirect_url_match?(host)
include Webrat::RedirectActions end
def follow_redirect_with_headers(h = {})
raise "Not a redirect! #{@status} #{@status_message}" unless redirect?
h['HTTP_REFERER'] = current_url if current_url
get(interpret_uri(headers["location"].first), {}, h)
status
end end
end end
end end
IntegrationTest.class_eval do IntegrationTest.class_eval do
include Webrat::Methods include Webrat::Methods
include Webrat::Matchers include Webrat::Matchers

View File

@ -1,18 +0,0 @@
# For Rails before http://dev.rubyonrails.org/ticket/10497 was committed
module Webrat
module RedirectActions #:nodoc:
def put_via_redirect(path, parameters = {}, headers = {})
put path, parameters, headers
follow_redirect! while redirect?
status
end
def delete_via_redirect(path, parameters = {}, headers = {})
delete path, parameters, headers
follow_redirect! while redirect?
status
end
end
end

View File

@ -1,88 +1,186 @@
require File.expand_path(File.dirname(__FILE__) + '/helper') require File.expand_path(File.dirname(__FILE__) + '/helper')
describe Webrat::RailsSession do describe Webrat::RailsSession do
before :each do
@integration_session = mock("integration_session")
@integration_session.stub!(:internal_redirect?)
@integration_session.stub!(:status)
end
it "should delegate response_body to the session response body" do it "should delegate response_body to the session response body" do
response = mock("response", :body => "<html>") @integration_session.stub!(:response => mock("response", :body => "<html>"))
integration_session = mock("integration session", :response => response) Webrat::RailsSession.new(@integration_session).response_body.should == "<html>"
Webrat::RailsSession.new(integration_session).response_body.should == "<html>"
end end
it "should delegate response_code to the session response code" do it "should delegate response_code to the session response code" do
response = mock("response", :code => "42") @integration_session.stub!(:response => mock("response", :code => "42"))
integration_session = mock("integration session", :response => response) Webrat::RailsSession.new(@integration_session).response_code.should == 42
Webrat::RailsSession.new(integration_session).response_code.should == 42
end end
it "should delegate get to request_via_redirect on the integration session" do it "should delegate get to the integration session" do
integration_session = mock("integration session") @integration_session.should_receive(:get).with("url", "data", "headers")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(@integration_session)
integration_session.should_receive(:request_via_redirect).with(:get, "url", "data", "headers")
rails_session.get("url", "data", "headers") rails_session.get("url", "data", "headers")
end end
it "should delegate post to request_via_redirect on the integration session" do it "should delegate post to the integration session" do
integration_session = mock("integration session") @integration_session.should_receive(:post).with("url", "data", "headers")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(@integration_session)
integration_session.should_receive(:request_via_redirect).with(:post, "url", "data", "headers")
rails_session.post("url", "data", "headers") rails_session.post("url", "data", "headers")
end end
it "should delegate put to request_via_redirect on the integration session" do it "should delegate put to the integration session" do
integration_session = mock("integration session") @integration_session.should_receive(:put).with("url", "data", "headers")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(@integration_session)
integration_session.should_receive(:request_via_redirect).with(:put, "url", "data", "headers")
rails_session.put("url", "data", "headers") rails_session.put("url", "data", "headers")
end end
it "should delegate delete to request_via_redirect on the integration session" do it "should delegate delete to the integration session" do
integration_session = mock("integration session") @integration_session.should_receive(:delete).with("url", "data", "headers")
rails_session = Webrat::RailsSession.new(integration_session) rails_session = Webrat::RailsSession.new(@integration_session)
integration_session.should_receive(:request_via_redirect).with(:delete, "url", "data", "headers")
rails_session.delete("url", "data", "headers") rails_session.delete("url", "data", "headers")
end end
context "the URL is a full path" do context "the URL is a full path" do
it "should just pass on the path" do it "should just pass on the path" do
integration_session = mock("integration session", :https! => nil) @integration_session.stub!(:https!)
rails_session = Webrat::RailsSession.new(integration_session) @integration_session.should_receive(:get).with("/url", "data", "headers")
integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers") rails_session = Webrat::RailsSession.new(@integration_session)
rails_session.get("http://www.example.com/url", "data", "headers") rails_session.get("http://www.example.com/url", "data", "headers")
end end
end end
context "the URL is https://" do context "the URL is https://" do
it "should call #https! with true before the request and just pass on the path" do it "should call #https! with true before the request and just pass on the path" do
integration_session = mock("integration session") @integration_session.should_receive(:https!).with(true)
rails_session = Webrat::RailsSession.new(integration_session) @integration_session.should_receive(:get).with("/url", "data", "headers")
integration_session.should_receive(:https!).with(true) rails_session = Webrat::RailsSession.new(@integration_session)
integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers")
rails_session.get("https://www.example.com/url", "data", "headers") rails_session.get("https://www.example.com/url", "data", "headers")
end end
end end
context "the URL is http://" do context "the URL is http://" do
it "should call #https! with true before the request" do it "should call #https! with true before the request" do
integration_session = mock("integration session", :request_via_redirect => nil) @integration_session.stub!(:get)
rails_session = Webrat::RailsSession.new(integration_session) @integration_session.should_receive(:https!).with(false)
integration_session.should_receive(:https!).with(false) rails_session = Webrat::RailsSession.new(@integration_session)
rails_session.get("http://www.example.com/url", "data", "headers") rails_session.get("http://www.example.com/url", "data", "headers")
end end
end end
context "the URL include an anchor" do context "the URL include an anchor" do
it "should strip out the anchor" do it "should strip out the anchor" do
integration_session = mock("integration session", :https! => false) @integration_session.should_receive(:https!).with(false)
rails_session = Webrat::RailsSession.new(integration_session) @integration_session.should_receive(:get).with("/url", "data", "headers")
integration_session.should_receive(:request_via_redirect).with(:get, "/url", "data", "headers") rails_session = Webrat::RailsSession.new(@integration_session)
rails_session.get("http://www.example.com/url#foo", "data", "headers") rails_session.get("http://www.example.com/url#foo", "data", "headers")
end end
end end
context "following redirects" do
it "should use forward headers when following redirects" do
@integration_session.stub!(:post)
@integration_session.stub!(:host)
@integration_session.stub!(:status)
@integration_session.should_receive(:internal_redirect?).twice.and_return(true, false)
@integration_session.should_receive(:follow_redirect_with_headers).with("headers")
rails_session = Webrat::RailsSession.new(@integration_session)
rails_session.post("url", "data", "headers")
end
it "should follow internal redirects" do
@integration_session.stub!(:get)
@integration_session.stub!(:host)
@integration_session.stub!(:status)
@integration_session.should_receive(:internal_redirect?).twice.and_return(true, false)
@integration_session.should_receive(:follow_redirect_with_headers)
rails_session = Webrat::RailsSession.new(@integration_session)
rails_session.get("url", "data", "headers")
end
it "should not follow external redirects" do
@integration_session.stub!(:get)
@integration_session.stub!(:host)
@integration_session.stub!(:status)
@integration_session.should_receive(:internal_redirect?).and_return(false)
@integration_session.should_not_receive(:follow_redirect_with_headers)
rails_session = Webrat::RailsSession.new(@integration_session)
rails_session.get("url", "data", "headers")
end
end
it "should provide a saved_page_dir" do it "should provide a saved_page_dir" do
Webrat::RailsSession.new(mock("integration session")).should respond_to(:saved_page_dir) Webrat::RailsSession.new(mock("integration session")).should respond_to(:saved_page_dir)
end end
it "should provide a doc_root" do it "should provide a doc_root" do
Webrat::RailsSession.new(mock("integration session")).should respond_to(:doc_root) Webrat::RailsSession.new(mock("integration session")).should respond_to(:doc_root)
end end
end
describe ActionController::Integration::Session do
before :each do
@integration_session = ActionController::Integration::Session.new
@integration_session.stub!(:response => mock("response"))
end
describe "internal_redirect?" do
it "should return false if the response is not a redirect" do
@integration_session.should_receive(:redirect?).and_return(false)
@integration_session.internal_redirect?.should == false
end
it "should return false if the response was a redirect but the response location does not match the request host" do
@integration_session.should_receive(:redirect?).and_return(true)
@integration_session.response.should_receive(:redirect_url_match?).and_return(false)
@integration_session.internal_redirect?.should == false
end
it "should return true if the response is a redirect and the response location matches the request host" do
@integration_session.should_receive(:redirect?).and_return(true)
@integration_session.response.should_receive(:redirect_url_match?).and_return(true)
@integration_session.internal_redirect?.should == true
end
end
describe "follow_redirect_with_headers" do
before do
@integration_session.stub!(:headers).and_return({ 'location' => ["/"]})
@integration_session.stub!(:redirect?).and_return true
@integration_session.stub!(:get)
end
it "should raise an exception if response wasn't a redirect" do
@integration_session.stub!(:redirect?).and_return false
lambda { @integration_session.follow_redirect_with_headers }.should raise_error
end
it "should set the HTTP referer header" do
@integration_session.stub!(:current_url).and_return "http://source.url/"
headers = {}
@integration_session.follow_redirect_with_headers(headers)
headers["HTTP_REFERER"].should == "http://source.url/"
end
it "should GET the first location header" do
@integration_session.stub!("headers").and_return({ 'location' => ['/target'] })
@integration_session.should_receive(:get).with("/target", {}, hash_including("headers" => "foo"))
@integration_session.follow_redirect_with_headers({"headers" => "foo"})
end
it "should return the status" do
@integration_session.stub!(:status).and_return "202"
@integration_session.follow_redirect_with_headers.should == "202"
end
end
end end

View File

@ -1,20 +0,0 @@
# it "should default to current url" do
# # current_page.stub!(:url => "/page")
# response_body = <<-HTML
# <form method="get">
# <input type="submit" />
# </form>
# HTML
# @page.stub!(:url => "/current")
# webrat_session.should_receive(:get).with("/current", {})
# click_button
# end
#
# it "should follow fully qualified secure local links" do
# response_body = <<-HTML
# <a href="https://www.example.com/page/sub">Jump to sub page</a>
# HTML
# webrat_session.should_receive(:https!).with(true)
# webrat_session.should_receive(:get).with("/page/sub", {})
# click_link "Jump to sub page"
# end