3 module ActionController
6 ENV_SESSION_KEY
= 'rack.session'.freeze
7 ENV_SESSION_OPTIONS_KEY
= 'rack.session.options'.freeze
9 HTTP_COOKIE
= 'HTTP_COOKIE'.freeze
10 SET_COOKIE
= 'Set-Cookie'.freeze
12 class SessionHash
< Hash
13 def initialize(by
, env)
21 ActiveSupport
::Deprecation.warn(
22 "ActionController::Session::AbstractStore::SessionHash#session_id " +
23 "has been deprecated. Please use request.session_options[:id] instead.", caller
)
24 @env[ENV_SESSION_OPTIONS_KEY
][:id]
39 h
.delete_if
{ |k
,v
| v
.nil? }
44 ActiveSupport
::Deprecation.warn(
45 "ActionController::Session::AbstractStore::SessionHash#data " +
46 "has been deprecated. Please use #to_hash instead.", caller
)
61 stale_session_check
! do
62 id
, session
= @by.send(:load_session, @env)
63 (@env[ENV_SESSION_OPTIONS_KEY
] ||= {})[:id] = id
69 def stale_session_check
!
71 rescue ArgumentError
=> argument_error
72 if argument_error
.message
=~
%r
{undefined
class/module ([\w
:]*\w
)}
74 # Note that the regexp does not allow $1 to end with a ':'
76 rescue LoadError
, NameError
=> const_error
77 raise ActionController
::SessionRestoreError, "Session contains objects whose class definition isn\\'t available.\nRemember to require the classes for all objects kept in the session.\n(Original exception: \#{const_error.message} [\#{const_error.class}])\n"
88 :key => '_session_id',
97 def initialize(app
, options
= {})
98 # Process legacy CGI options
99 options
= options
.symbolize_keys
100 if options
.has_key
?(:session_path)
101 options
[:path] = options
.delete(:session_path)
103 if options
.has_key
?(:session_key)
104 options
[:key] = options
.delete(:session_key)
106 if options
.has_key
?(:session_http_only)
107 options
[:httponly] = options
.delete(:session_http_only)
111 @default_options = DEFAULT_OPTIONS
.merge(options
)
112 @key = @default_options[:key]
113 @cookie_only = @default_options[:cookie_only]
117 session
= SessionHash
.new(self, env)
119 env[ENV_SESSION_KEY
] = session
120 env[ENV_SESSION_OPTIONS_KEY
] = @default_options.dup
122 response
= @app.call(env)
124 session_data
= env[ENV_SESSION_KEY
]
125 options
= env[ENV_SESSION_OPTIONS_KEY
]
127 if !session_data
.is_a
?(AbstractStore
::SessionHash) || session_data
.send(:loaded?) || options
[:expire_after]
128 session_data
.send(:load!) if session_data
.is_a
?(AbstractStore
::SessionHash) && !session_data
.send(:loaded?)
130 sid
= options
[:id] || generate_sid
132 unless set_session(env, sid
, session_data
.to_hash
)
136 cookie
= Rack
::Utils.escape(@key) + '=' + Rack
::Utils.escape(sid
)
137 cookie
<< "; domain=#{options[:domain]}" if options
[:domain]
138 cookie
<< "; path=#{options[:path]}" if options
[:path]
139 if options
[:expire_after]
140 expiry
= Time
.now
+ options
[:expire_after]
141 cookie
<< "; expires=#{expiry.httpdate}"
143 cookie
<< "; Secure" if options
[:secure]
144 cookie
<< "; HttpOnly" if options
[:httponly]
146 headers
= response
[1]
147 unless headers
[SET_COOKIE
].blank
?
148 headers
[SET_COOKIE
] << "\n#{cookie}"
150 headers
[SET_COOKIE
] = cookie
159 ActiveSupport
::SecureRandom.hex(16)
162 def load_session(env)
163 request
= Rack
::Request.new(env)
164 sid
= request
.cookies
[@key]
166 sid
||= request
.params
[@key]
168 sid
, session
= get_session(env, sid
)
172 def get_session(env, sid
)
173 raise '#get_session needs to be implemented.'
176 def set_session(env, sid
, session_data
)
177 raise '#set_session needs to be implemented.'