diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2008-12-15 18:22:35 -0800 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2008-12-15 18:22:35 -0800 |
commit | 89056885b030b981193d73ebde56cf60829a924c (patch) | |
tree | 9d432f7226754115ac4d2ef8aa1134221ff294bb /actionpack/lib/action_controller/session/abstract_store.rb | |
parent | 19be3d35b38b6685789d8d343617d465a3652717 (diff) | |
parent | 43ac42c46a462e1453b1b97da00e11bff7bba55d (diff) | |
download | rails-89056885b030b981193d73ebde56cf60829a924c.tar.gz rails-89056885b030b981193d73ebde56cf60829a924c.tar.bz2 rails-89056885b030b981193d73ebde56cf60829a924c.zip |
Merge branch 'master' of git@github.com:rails/rails
Diffstat (limited to 'actionpack/lib/action_controller/session/abstract_store.rb')
-rw-r--r-- | actionpack/lib/action_controller/session/abstract_store.rb | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/actionpack/lib/action_controller/session/abstract_store.rb b/actionpack/lib/action_controller/session/abstract_store.rb new file mode 100644 index 0000000000..c6dd865fad --- /dev/null +++ b/actionpack/lib/action_controller/session/abstract_store.rb @@ -0,0 +1,131 @@ +require 'rack/utils' + +module ActionController + module Session + class AbstractStore + ENV_SESSION_KEY = 'rack.session'.freeze + ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze + + HTTP_COOKIE = 'HTTP_COOKIE'.freeze + SET_COOKIE = 'Set-Cookie'.freeze + + class SessionHash < Hash + def initialize(by, env) + @by = by + @env = env + @loaded = false + end + + def id + load! unless @loaded + @id + end + + def [](key) + load! unless @loaded + super + end + + def []=(key, value) + load! unless @loaded + super + end + + def to_hash + h = {}.replace(self) + h.delete_if { |k,v| v.nil? } + h + end + + private + def load! + @id, session = @by.send(:load_session, @env) + replace(session) + @loaded = true + end + end + + DEFAULT_OPTIONS = { + :key => 'rack.session', + :path => '/', + :domain => nil, + :expire_after => nil, + :secure => false, + :httponly => true, + :cookie_only => true + } + + def initialize(app, options = {}) + @app = app + @default_options = DEFAULT_OPTIONS.merge(options) + @key = @default_options[:key] + @cookie_only = @default_options[:cookie_only] + end + + def call(env) + session = SessionHash.new(self, env) + original_session = session.dup + + env[ENV_SESSION_KEY] = session + env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup + + response = @app.call(env) + + session = env[ENV_SESSION_KEY] + unless session == original_session + options = env[ENV_SESSION_OPTIONS_KEY] + sid = session.id + + unless set_session(env, sid, session.to_hash) + return response + end + + cookie = Rack::Utils.escape(@key) + '=' + Rack::Utils.escape(sid) + cookie << "; domain=#{options[:domain]}" if options[:domain] + cookie << "; path=#{options[:path]}" if options[:path] + if options[:expire_after] + expiry = Time.now + options[:expire_after] + cookie << "; expires=#{expiry.httpdate}" + end + cookie << "; Secure" if options[:secure] + cookie << "; HttpOnly" if options[:httponly] + + headers = response[1] + case a = headers[SET_COOKIE] + when Array + a << cookie + when String + headers[SET_COOKIE] = [a, cookie] + when nil + headers[SET_COOKIE] = cookie + end + end + + response + end + + private + def generate_sid + ActiveSupport::SecureRandom.hex(16) + end + + def load_session(env) + request = Rack::Request.new(env) + sid = request.cookies[@key] + unless @cookie_only + sid ||= request.params[@key] + end + sid, session = get_session(env, sid) + [sid, session] + end + + def get_session(env, sid) + raise '#get_session needs to be implemented.' + end + + def set_session(env, sid, session_data) + raise '#set_session needs to be implemented.' + end + end + end +end |