diff --git a/lib/rack/test.rb b/lib/rack/test.rb index d90104b3..846c223f 100644 --- a/lib/rack/test.rb +++ b/lib/rack/test.rb @@ -4,7 +4,8 @@ require "rack/test/cookie_jar" require "rack/test/mock_digest_request" require "rack/test/utils" -require "rack/test/methods" +load '/Users/daris/Documents/uxtemple/opensource/rack-test/lib/rack/test/methods.rb' +# require "rack/test/methods" require "rack/test/uploaded_file" module Rack @@ -35,6 +36,7 @@ class Session # (See README.rdoc for an example) def initialize(mock_session) @headers = {} + @env = {} if mock_session.is_a?(MockSession) @rack_mock_session = mock_session @@ -139,6 +141,19 @@ def header(name, value) end end + # Set an env var to be included on all subsequent requests through the + # session. Use a value of nil to remove a previously configured env. + # + # Example: + # env "rack.session", {:csrf => 'token'} + def env(name, value) + if value.nil? + @env.delete(name) + else + @env[name] = value + end + end + # Set the username and password for HTTP Basic authorization, to be # included in subsequent requests in the HTTP_AUTHORIZATION header. # @@ -173,6 +188,12 @@ def follow_redirect! get(last_response["Location"], {}, { "HTTP_REFERER" => last_request.url }) end + # Set a CSRF token so you can easily test safe services + def csrf(enable=true) + header('X-CSRF-Token', enable ? 'token' : nil) + env('rack.session', enable ? {:csrf => 'token'} : nil) + end + private def env_for(path, env) @@ -271,7 +292,7 @@ def digest_auth_configured? end def default_env - { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(headers_for_env) + { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(@env).merge(headers_for_env) end def headers_for_env diff --git a/lib/rack/test/methods.rb b/lib/rack/test/methods.rb index 5eb8b6bc..4ff569d3 100644 --- a/lib/rack/test/methods.rb +++ b/lib/rack/test/methods.rb @@ -67,11 +67,13 @@ def _current_session_names # :nodoc: :head, :follow_redirect!, :header, + :env, :set_cookie, :clear_cookies, :authorize, :basic_authorize, :digest_authorize, + :csrf, :last_response, :last_request ] diff --git a/spec/rack/test_spec.rb b/spec/rack/test_spec.rb index 73086da0..08bd5dcf 100644 --- a/spec/rack/test_spec.rb +++ b/spec/rack/test_spec.rb @@ -237,10 +237,10 @@ def close describe "#header" do it "sets a header to be sent with requests" do - header "User-Agent", "Firefox" + header "User-Agent", "token" request "/" - last_request.env["HTTP_USER_AGENT"].should == "Firefox" + last_request.env["HTTP_USER_AGENT"].should == "token" end it "sets a Content-Type to be sent with requests" do @@ -258,15 +258,15 @@ def close end it "persists across multiple requests" do - header "User-Agent", "Firefox" + header "User-Agent", "token" request "/" request "/" - last_request.env["HTTP_USER_AGENT"].should == "Firefox" + last_request.env["HTTP_USER_AGENT"].should == "token" end it "overwrites previously set headers" do - header "User-Agent", "Firefox" + header "User-Agent", "token" header "User-Agent", "Safari" request "/" @@ -274,7 +274,7 @@ def close end it "can be used to clear a header" do - header "User-Agent", "Firefox" + header "User-Agent", "token" header "User-Agent", nil request "/" @@ -282,13 +282,53 @@ def close end it "is overridden by headers sent during the request" do - header "User-Agent", "Firefox" + header "User-Agent", "token" request "/", "HTTP_USER_AGENT" => "Safari" last_request.env["HTTP_USER_AGENT"].should == "Safari" end end + describe "#env" do + it "sets the env to be sent with requests" do + env "rack.session", {:csrf => 'token'} + request "/" + + last_request.env["rack.session"].should == {:csrf => 'token'} + end + + it "persists across multiple requests" do + env "rack.session", {:csrf => 'token'} + request "/" + request "/" + + last_request.env["rack.session"].should == {:csrf => 'token'} + end + + it "overwrites previously set envs" do + env "rack.session", {:csrf => 'token'} + env "rack.session", {:some => :thing} + request "/" + + last_request.env["rack.session"].should == {:some => :thing} + end + + it "can be used to clear a env" do + env "rack.session", {:csrf => 'token'} + env "rack.session", nil + request "/" + + last_request.env.should_not have_key("X_CSRF_TOKEN") + end + + it "is overridden by envs sent during the request" do + env "rack.session", {:csrf => 'token'} + request "/", "rack.session" => {:some => :thing} + + last_request.env["rack.session"].should == {:some => :thing} + end + end + describe "#authorize" do it "sets the HTTP_AUTHORIZATION header" do authorize "bryan", "secret" @@ -338,6 +378,44 @@ def close end end + describe "#csrf" do + it "sets the HTTP_X_CSRF_TOKEN header" do + csrf + request "/" + + last_request.env["HTTP_X_CSRF_TOKEN"].should == "token" + end + + it "sets the rack.session to include CSRF token" do + csrf + request "/" + + last_request.env["rack.session"].should == {:csrf => "token"} + end + + it "includes the header & rack.session for subsequent requests" do + csrf + request "/" + request "/" + + last_request.env["HTTP_X_CSRF_TOKEN"].should == "token" + last_request.env["rack.session"].should == {:csrf => "token"} + end + + it "can be cleared out" do + csrf + request "/" + last_request.env["HTTP_X_CSRF_TOKEN"].should == "token" + last_request.env["rack.session"].should == {:csrf => "token"} + + csrf(false) + request "/" + + last_request.env.should_not have_key("HTTP_X_CSRF_TOKEN") + last_request.env.should_not have_key("rack.session") + end + end + describe "#last_request" do it "returns the most recent request" do request "/"