use a request object in the session middleware

This commit allows us to use one request object rather than allocating
multiple request objects to deal with the session.
This commit is contained in:
Aaron Patterson 2015-08-22 17:57:45 -07:00
parent 4f244f7cab
commit 5fe141638f
8 changed files with 77 additions and 71 deletions

View File

@ -27,7 +27,7 @@ GIT
GIT GIT
remote: git://github.com/rack/rack.git remote: git://github.com/rack/rack.git
revision: be777e06bf4de18a7786af1e44647e1498ec1a5d revision: c94e22401d4719b4d78378c7b63362cd692f9005
specs: specs:
rack (2.0.0.alpha) rack (2.0.0.alpha)
json json
@ -79,7 +79,7 @@ GIT
GIT GIT
remote: git://github.com/rails/sprockets.git remote: git://github.com/rails/sprockets.git
revision: 653de5268ba862ea23457291824180c67ad5dc99 revision: a61550db7184fc83964fb983547ff09da9efa9be
branch: master branch: master
specs: specs:
sprockets (4.0.0) sprockets (4.0.0)
@ -236,7 +236,7 @@ GEM
resque (~> 1.25) resque (~> 1.25)
rufus-scheduler (~> 3.0) rufus-scheduler (~> 3.0)
rufus-scheduler (3.1.3) rufus-scheduler (3.1.3)
sass (3.4.16) sass (3.4.17)
sdoc (0.4.1) sdoc (0.4.1)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
rdoc (~> 4.0) rdoc (~> 4.0)

View File

@ -314,11 +314,11 @@ module ActionDispatch
end end
def session=(session) #:nodoc: def session=(session) #:nodoc:
Session.set @env, session Session.set self, session
end end
def session_options=(options) def session_options=(options)
Session::Options.set @env, options Session::Options.set self, options
end end
# Override Rack's GET method to support indifferent access # Override Rack's GET method to support indifferent access

View File

@ -274,7 +274,7 @@ module ActionDispatch
req = ActionDispatch::Request.new env req = ActionDispatch::Request.new env
@app.call(env) @app.call(env)
ensure ensure
session = Request::Session.find(env) || {} session = Request::Session.find(req) || {}
flash_hash = req.flash_hash flash_hash = req.flash_hash
if flash_hash && (flash_hash.present? || session.key?('flash')) if flash_hash && (flash_hash.present? || session.key?('flash'))

View File

@ -36,6 +36,11 @@ module ActionDispatch
@default_options.delete(:sidbits) @default_options.delete(:sidbits)
@default_options.delete(:secure_random) @default_options.delete(:secure_random)
end end
private
def make_request(env)
ActionDispatch::Request.new env
end
end end
module StaleSessionCheck module StaleSessionCheck
@ -65,8 +70,8 @@ module ActionDispatch
end end
module SessionObject # :nodoc: module SessionObject # :nodoc:
def prepare_session(env) def prepare_session(req)
Request::Session.create(self, env, @default_options) Request::Session.create(self, req, @default_options)
end end
def loaded_session?(session) def loaded_session?(session)
@ -81,8 +86,7 @@ module ActionDispatch
private private
def set_cookie(env, session_id, cookie) def set_cookie(request, session_id, cookie)
request = ActionDispatch::Request.new(env)
request.cookie_jar[key] = cookie request.cookie_jar[key] = cookie
end end
end end

View File

@ -71,16 +71,16 @@ module ActionDispatch
super(app, options.merge!(:cookie_only => true)) super(app, options.merge!(:cookie_only => true))
end end
def destroy_session(env, session_id, options) def destroy_session(req, session_id, options)
new_sid = generate_sid unless options[:drop] new_sid = generate_sid unless options[:drop]
# Reset hash and Assign the new session id # Reset hash and Assign the new session id
env["action_dispatch.request.unsigned_session_cookie"] = new_sid ? { "session_id" => new_sid } : {} req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid } : {})
new_sid new_sid
end end
def load_session(env) def load_session(req)
stale_session_check! do stale_session_check! do
data = unpacked_cookie_data(env) data = unpacked_cookie_data(req)
data = persistent_session_id!(data) data = persistent_session_id!(data)
[data["session_id"], data] [data["session_id"], data]
end end
@ -88,20 +88,21 @@ module ActionDispatch
private private
def extract_session_id(env) def extract_session_id(req)
stale_session_check! do stale_session_check! do
unpacked_cookie_data(env)["session_id"] unpacked_cookie_data(req)["session_id"]
end end
end end
def unpacked_cookie_data(env) def unpacked_cookie_data(req)
env["action_dispatch.request.unsigned_session_cookie"] ||= begin req.get_header("action_dispatch.request.unsigned_session_cookie") do |k|
stale_session_check! do v = stale_session_check! do
if data = get_cookie(env) if data = get_cookie(req)
data.stringify_keys! data.stringify_keys!
end end
data || {} data || {}
end end
req.set_header k, v
end end
end end
@ -111,21 +112,20 @@ module ActionDispatch
data data
end end
def set_session(env, sid, session_data, options) def set_session(req, sid, session_data, options)
session_data["session_id"] = sid session_data["session_id"] = sid
session_data session_data
end end
def set_cookie(env, session_id, cookie) def set_cookie(request, session_id, cookie)
cookie_jar(env)[@key] = cookie cookie_jar(request)[@key] = cookie
end end
def get_cookie(env) def get_cookie(req)
cookie_jar(env)[@key] cookie_jar(req)[@key]
end end
def cookie_jar(env) def cookie_jar(request)
request = ActionDispatch::Request.new(env)
request.cookie_jar.signed_or_encrypted request.cookie_jar.signed_or_encrypted
end end
end end

View File

@ -11,31 +11,31 @@ module ActionDispatch
Unspecified = Object.new Unspecified = Object.new
# Creates a session hash, merging the properties of the previous session if any # Creates a session hash, merging the properties of the previous session if any
def self.create(store, env, default_options) def self.create(store, req, default_options)
session_was = find env session_was = find req
session = Request::Session.new(store, env) session = Request::Session.new(store, req)
session.merge! session_was if session_was session.merge! session_was if session_was
set(env, session) set(req, session)
Options.set(env, Request::Session::Options.new(store, default_options)) Options.set(req, Request::Session::Options.new(store, default_options))
session session
end end
def self.find(env) def self.find(req)
env[ENV_SESSION_KEY] req.get_header ENV_SESSION_KEY
end end
def self.set(env, session) def self.set(req, session)
env[ENV_SESSION_KEY] = session req.set_header ENV_SESSION_KEY, session
end end
class Options #:nodoc: class Options #:nodoc:
def self.set(env, options) def self.set(req, options)
env[ENV_SESSION_OPTIONS_KEY] = options req.set_header ENV_SESSION_OPTIONS_KEY, options
end end
def self.find(env) def self.find(req)
env[ENV_SESSION_OPTIONS_KEY] req.get_header ENV_SESSION_OPTIONS_KEY
end end
def initialize(by, default_options) def initialize(by, default_options)
@ -47,9 +47,9 @@ module ActionDispatch
@delegate[key] @delegate[key]
end end
def id(env) def id(req)
@delegate.fetch(:id) { @delegate.fetch(:id) {
@by.send(:extract_session_id, env) @by.send(:extract_session_id, req)
} }
end end
@ -58,26 +58,26 @@ module ActionDispatch
def values_at(*args); @delegate.values_at(*args); end def values_at(*args); @delegate.values_at(*args); end
end end
def initialize(by, env) def initialize(by, req)
@by = by @by = by
@env = env @req = req
@delegate = {} @delegate = {}
@loaded = false @loaded = false
@exists = nil # we haven't checked yet @exists = nil # we haven't checked yet
end end
def id def id
options.id(@env) options.id(@req)
end end
def options def options
Options.find @env Options.find @req
end end
def destroy def destroy
clear clear
options = self.options || {} options = self.options || {}
@by.send(:destroy_session, @env, options.id(@env), options) @by.send(:destroy_session, @req, options.id(@req), options)
# Load the new sid to be written with the response # Load the new sid to be written with the response
@loaded = false @loaded = false
@ -181,7 +181,7 @@ module ActionDispatch
def exists? def exists?
return @exists unless @exists.nil? return @exists unless @exists.nil?
@exists = @by.send(:session_exists?, @env) @exists = @by.send(:session_exists?, @req)
end end
def loaded? def loaded?
@ -209,7 +209,7 @@ module ActionDispatch
end end
def load! def load!
id, session = @by.load_session @env id, session = @by.load_session @req
options[:id] = id options[:id] = id
@delegate.replace(stringify_keys(session)) @delegate.replace(stringify_keys(session))
@loaded = true @loaded = true

View File

@ -4,40 +4,42 @@ require 'action_dispatch/middleware/session/abstract_store'
module ActionDispatch module ActionDispatch
class Request class Request
class SessionTest < ActiveSupport::TestCase class SessionTest < ActiveSupport::TestCase
attr_reader :req
def setup
@req = ActionDispatch::Request.new({})
end
def test_create_adds_itself_to_env def test_create_adds_itself_to_env
env = {} s = Session.create(store, req, {})
s = Session.create(store, env, {}) assert_equal s, req.env[Rack::RACK_SESSION]
assert_equal s, env[Rack::RACK_SESSION]
end end
def test_to_hash def test_to_hash
env = {} s = Session.create(store, req, {})
s = Session.create(store, env, {})
s['foo'] = 'bar' s['foo'] = 'bar'
assert_equal 'bar', s['foo'] assert_equal 'bar', s['foo']
assert_equal({'foo' => 'bar'}, s.to_hash) assert_equal({'foo' => 'bar'}, s.to_hash)
end end
def test_create_merges_old def test_create_merges_old
env = {} s = Session.create(store, req, {})
s = Session.create(store, env, {})
s['foo'] = 'bar' s['foo'] = 'bar'
s1 = Session.create(store, env, {}) s1 = Session.create(store, req, {})
assert_not_equal s, s1 assert_not_equal s, s1
assert_equal 'bar', s1['foo'] assert_equal 'bar', s1['foo']
end end
def test_find def test_find
env = {} assert_nil Session.find(req)
assert_nil Session.find(env)
s = Session.create(store, env, {}) s = Session.create(store, req, {})
assert_equal s, Session.find(env) assert_equal s, Session.find(req)
end end
def test_destroy def test_destroy
s = Session.create(store, {}, {}) s = Session.create(store, req, {})
s['rails'] = 'ftw' s['rails'] = 'ftw'
s.destroy s.destroy
@ -46,21 +48,21 @@ module ActionDispatch
end end
def test_keys def test_keys
s = Session.create(store, {}, {}) s = Session.create(store, req, {})
s['rails'] = 'ftw' s['rails'] = 'ftw'
s['adequate'] = 'awesome' s['adequate'] = 'awesome'
assert_equal %w[rails adequate], s.keys assert_equal %w[rails adequate], s.keys
end end
def test_values def test_values
s = Session.create(store, {}, {}) s = Session.create(store, req, {})
s['rails'] = 'ftw' s['rails'] = 'ftw'
s['adequate'] = 'awesome' s['adequate'] = 'awesome'
assert_equal %w[ftw awesome], s.values assert_equal %w[ftw awesome], s.values
end end
def test_clear def test_clear
s = Session.create(store, {}, {}) s = Session.create(store, req, {})
s['rails'] = 'ftw' s['rails'] = 'ftw'
s['adequate'] = 'awesome' s['adequate'] = 'awesome'
@ -69,7 +71,7 @@ module ActionDispatch
end end
def test_update def test_update
s = Session.create(store, {}, {}) s = Session.create(store, req, {})
s['rails'] = 'ftw' s['rails'] = 'ftw'
s.update(:rails => 'awesome') s.update(:rails => 'awesome')
@ -79,7 +81,7 @@ module ActionDispatch
end end
def test_delete def test_delete
s = Session.create(store, {}, {}) s = Session.create(store, req, {})
s['rails'] = 'ftw' s['rails'] = 'ftw'
s.delete('rails') s.delete('rails')
@ -88,7 +90,7 @@ module ActionDispatch
end end
def test_fetch def test_fetch
session = Session.create(store, {}, {}) session = Session.create(store, req, {})
session['one'] = '1' session['one'] = '1'
assert_equal '1', session.fetch(:one) assert_equal '1', session.fetch(:one)

View File

@ -27,7 +27,7 @@ module ActionDispatch
as.call(env) as.call(env)
assert @env assert @env
assert Request::Session.find @env assert Request::Session.find ActionDispatch::Request.new @env
end end
def test_new_session_object_is_merged_with_old def test_new_session_object_is_merged_with_old
@ -36,11 +36,11 @@ module ActionDispatch
as.call(env) as.call(env)
assert @env assert @env
session = Request::Session.find @env session = Request::Session.find ActionDispatch::Request.new @env
session['foo'] = 'bar' session['foo'] = 'bar'
as.call(@env) as.call(@env)
session1 = Request::Session.find @env session1 = Request::Session.find ActionDispatch::Request.new @env
assert_not_equal session, session1 assert_not_equal session, session1
assert_equal session.to_hash, session1.to_hash assert_equal session.to_hash, session1.to_hash