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.

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

default_options[R]
key[R]

Public Class Methods

new(app, options={}) click to toggle source
# 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

call(env) click to toggle source
# File lib/rack/session/abstract/id.rb, line 204
def call(env)
  context(env)
end
context(env, app=@app) click to toggle source
# 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

commit_session(env, status, headers, body) click to toggle source

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
commit_session?(env, session, options) click to toggle source

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
current_session_id(env) click to toggle source

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
destroy_session(env, sid, options) click to toggle source

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(env) click to toggle source

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
force_options?(options) click to toggle source
# File lib/rack/session/abstract/id.rb, line 297
def force_options?(options)
  options.values_at(:renew, :drop, :defer, :expire_after).any?
end
forced_session_update?(session, options) click to toggle source
# File lib/rack/session/abstract/id.rb, line 293
def forced_session_update?(session, options)
  force_options?(options) && session && !session.empty?
end
generate_sid(secure = @sid_secure) click to toggle source

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
get_session(env, sid) click to toggle source

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
initialize_sid() click to toggle source
# 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
load_session(env) click to toggle source

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
loaded_session?(session) click to toggle source
# File lib/rack/session/abstract/id.rb, line 289
def loaded_session?(session)
  !session.is_a?(SessionHash) || session.loaded?
end
prepare_session(env) click to toggle source

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
security_matches?(env, options) click to toggle source
# 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
session_exists?(env) click to toggle source

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
set_session(env, sid, session, options) click to toggle source

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