1 # AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
3 # apeiros, for session id generation, expiry setup, and threadiness
4 # sergio, threadiness and bugreps
6 require 'rack/session/abstract/id'
11 # Rack::Session::Pool provides simple cookie based session management.
12 # Session data is stored in a hash held by @pool.
13 # In the context of a multithreaded environment, sessions being
14 # committed to the pool is done in a merging manner.
16 # The :drop option is available in rack.session.options if you with to
17 # explicitly remove the session from the session cache.
20 # myapp = MyRackApp.new
21 # sessioned = Rack::Session::Pool.new(myapp,
22 # :domain => 'foo.com',
23 # :expire_after => 2592000
25 # Rack::Handler::WEBrick.run sessioned
27 class Pool
< Abstract
::ID
28 attr_reader
:mutex, :pool
29 DEFAULT_OPTIONS
= Abstract
::ID::DEFAULT_OPTIONS.merge
:drop => false
31 def initialize(app
, options
={})
40 break sid
unless @pool.key
? sid
44 def get_session(env, sid
)
45 session
= @pool[sid
] if sid
46 @mutex.lock
if env['rack.multithread']
47 unless sid
and session
48 env['rack.errors'].puts("Session '#{sid.inspect}' not found, initializing...") if $VERBOSE and not sid
.nil?
51 @pool.store sid
, session
53 session
.instance_variable_set('@old', {}.merge(session
))
56 @mutex.unlock
if env['rack.multithread']
59 def set_session(env, session_id
, new_session
, options
)
60 @mutex.lock
if env['rack.multithread']
61 session
= @pool[session_id
]
62 if options
[:renew] or options
[:drop]
63 @pool.delete session_id
64 return false if options
[:drop]
65 session_id
= generate_sid
66 @pool.store session_id
, 0
68 old_session
= new_session
.instance_variable_get('@old') || {}
69 session
= merge_sessions session_id
, old_session
, new_session
, session
70 @pool.store session_id
, session
73 warn
"#{new_session.inspect} has been lost."
76 @mutex.unlock
if env['rack.multithread']
81 def merge_sessions sid
, old
, new
, cur
=nil
83 unless Hash
=== old
and Hash
=== new
84 warn
'Bad old or new sessions provided.'
88 delete
= old
.keys
- new
.keys
89 warn
"//@#{sid}: dropping #{delete*','}" if $DEBUG and not delete
.empty
?
90 delete
.each
{|k
| cur
.delete k
}
92 update
= new
.keys
.select
{|k
| new
[k
] != old
[k
] }
93 warn
"//@#{sid}: updating #{update*','}" if $DEBUG and not update
.empty
?
94 update
.each
{|k
| cur
[k
] = new
[k
] }