class Rack::Session::Abstract::ID
ID sets up a basic framework for implementing an id based sessioning service. Cookies sent to the client for maintaining sessions will only contain an id reference. Only get_session and set_session are required to be overwritten.
All parameters are optional.
-
:key determines the name of the cookie, by default it is 'rack.session'
-
:path, :domain, :expire_after, :secure, and :httponly set the related cookie options as by Rack::Response#add_cookie
-
:skip will not a set a cookie in the response nor update the session state
-
:defer will not set a cookie in the response but still update the session state if it is used with a backend
-
:renew (implementation dependent) will prompt the generation of a new session id, and migration of data to be referenced at the new id. If :defer is set, it will be overridden and the cookie will be set.
-
:sidbits sets the number of bits in length that a generated session id will be.
These options can be set on a per request basis, at the location of env. Additionally the id of the session can be found within the options hash at the key :id. It is highly not recommended to change its value.
Is Rack::Utils::Context compatible.
Not included by default; you must require 'rack/session/abstract/id' to use.
Constants
- DEFAULT_OPTIONS
Attributes
Public Class Methods
# File lib/rack/session/abstract/id.rb, line 196 def initialize(app, options={}) @app = app @default_options = self.class::DEFAULT_OPTIONS.merge(options) @key = @default_options.delete(:key) @cookie_only = @default_options.delete(:cookie_only) initialize_sid end
Public Instance Methods
# File lib/rack/session/abstract/id.rb, line 204 def call(env) context(env) end
# File lib/rack/session/abstract/id.rb, line 208 def context(env, app=@app) prepare_session(env) status, headers, body = app.call(env) commit_session(env, status, headers, body) end
Private Instance Methods
Acquires the session from the environment and the session id from the session options and passes them to set_session. If successful and the :defer option is not true, a cookie will be added to the response with the session's id.
# File lib/rack/session/abstract/id.rb, line 312 def commit_session(env, status, headers, body) session = env['rack.session'] options = env['rack.session.options'] if options[:drop] || options[:renew] session_id = destroy_session(env, options[:id] || generate_sid, options) return [status, headers, body] unless session_id end return [status, headers, body] unless commit_session?(env, session, options) session.send(:load!) unless loaded_session?(session) session = session.to_hash session_id ||= options[:id] || generate_sid if not data = set_session(env, session_id, session, options) env["rack.errors"].puts("Warning! #{self.class.name} failed to save session. Content dropped.") elsif options[:defer] and not options[:renew] env["rack.errors"].puts("Defering cookie for #{session_id}") if $VERBOSE else cookie = Hash.new cookie[:value] = data cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after] set_cookie(env, headers, cookie.merge!(options)) end [status, headers, body] end
Session should be commited if it was loaded, any of specific options like :renew, :drop or :expire_after was given and the security permissions match. Skips if skip is given.
# File lib/rack/session/abstract/id.rb, line 280 def commit_session?(env, session, options) if options[:skip] false else has_session = loaded_session?(session) || forced_session_update?(session, options) has_session && security_matches?(env, options) end end
Returns the current session id from the OptionsHash.
# File lib/rack/session/abstract/id.rb, line 266 def current_session_id(env) env[ENV_SESSION_OPTIONS_KEY][:id] end
All thread safety and session destroy proceedures should occur here. Should return a new session id or nil if options
# File lib/rack/session/abstract/id.rb, line 371 def destroy_session(env, sid, options) raise '#destroy_session not implemented' end
Extract session id from request object.
# File lib/rack/session/abstract/id.rb, line 257 def extract_session_id(env) request = Rack::Request.new(env) sid = request.cookies[@key] sid ||= request.params[@key] unless @cookie_only sid end
# File lib/rack/session/abstract/id.rb, line 297 def force_options?(options) options.values_at(:renew, :drop, :defer, :expire_after).any? end
# File lib/rack/session/abstract/id.rb, line 293 def forced_session_update?(session, options) force_options?(options) && session && !session.empty? end
Generate a new session id using Ruby rand. The size of the session id is controlled by the :sidbits option. Monkey patch this to use custom methods for session id generation.
# File lib/rack/session/abstract/id.rb, line 226 def generate_sid(secure = @sid_secure) if secure SecureRandom.hex(@sid_length) else "%0#{@sid_length}x" % Kernel.rand(2**@sidbits - 1) end rescue NotImplementedError generate_sid(false) end
All thread safety and session retrival proceedures should occur here. Should return [session_id, session]. If nil is provided as the session id, generation of a new valid id should occur within.
# File lib/rack/session/abstract/id.rb, line 356 def get_session(env, sid) raise '#get_session not implemented.' end
# File lib/rack/session/abstract/id.rb, line 216 def initialize_sid @sidbits = @default_options[:sidbits] @sid_secure = @default_options[:secure_random] @sid_length = @sidbits / 4 end
Extracts the session id from provided cookies and passes it and the environment to get_session.
# File lib/rack/session/abstract/id.rb, line 249 def load_session(env) sid = current_session_id(env) sid, session = get_session(env, sid) [sid, session || {}] end
# File lib/rack/session/abstract/id.rb, line 289 def loaded_session?(session) !session.is_a?(SessionHash) || session.loaded? end
Sets the lazy session at 'rack.session' and places options and session metadata into 'rack.session.options'.
# File lib/rack/session/abstract/id.rb, line 239 def prepare_session(env) session_was = env[ENV_SESSION_KEY] env[ENV_SESSION_KEY] = SessionHash.new(self, env) env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options) env[ENV_SESSION_KEY].merge! session_was if session_was end
# File lib/rack/session/abstract/id.rb, line 301 def security_matches?(env, options) return true unless options[:secure] request = Rack::Request.new(env) request.ssl? end
Check if the session exists or not.
# File lib/rack/session/abstract/id.rb, line 272 def session_exists?(env) value = current_session_id(env) value && !value.empty? end
All thread safety and session storage proceedures should occur here. Should return true or false dependant on whether or not the session was saved or not.
# File lib/rack/session/abstract/id.rb, line 364 def set_session(env, sid, session, options) raise '#set_session not implemented.' end