Skip to content

Commit

Permalink
Merge pull request #342 from brainopia/e5b4d961e5cb310bffca18a2cf72a1…
Browse files Browse the repository at this point in the history
…1b1075f8bd

Rack::Session remove inheritance from Hash
  • Loading branch information
raggi committed Nov 3, 2012
2 parents c4fc616 + a826b46 commit 75b358c
Showing 1 changed file with 45 additions and 49 deletions.
94 changes: 45 additions & 49 deletions lib/rack/session/abstract/id.rb
Expand Up @@ -18,96 +18,93 @@ module Abstract
ENV_SESSION_KEY = 'rack.session'.freeze
ENV_SESSION_OPTIONS_KEY = 'rack.session.options'.freeze

# Thin wrapper around Hash that allows us to lazily load session id into session_options.
# SessionHash is responsible to lazily load the session from store.

class SessionHash
include Enumerable
attr_writer :id

class OptionsHash < Hash #:nodoc:
def initialize(by, env, default_options)
def initialize(by, env)
@by = by
@env = env
@session_id_loaded = false
merge!(default_options)
end

def [](key)
load_session_id! if key == :id && session_id_not_loaded?
super
@loaded = false
end

private

def session_id_not_loaded?
!(@session_id_loaded || key?(:id))
def id
return @id if @loaded or instance_variable_defined?(:@id)
@id = @by.send(:extract_session_id, @env)
end

def load_session_id!
self[:id] = @by.send(:extract_session_id, @env)
@session_id_loaded = true
def options
@env[ENV_SESSION_OPTIONS_KEY]
end
end

# SessionHash is responsible to lazily load the session from store.

class SessionHash < Hash
def initialize(by, env)
super()
@by = by
@env = env
@loaded = false
def each(&block)
load_for_read!
@data.each(&block)
end

def [](key)
load_for_read!
super(key.to_s)
@data[key.to_s]
end
alias :fetch :[]

def has_key?(key)
load_for_read!
super(key.to_s)
@data.has_key?(key.to_s)
end
alias :key? :has_key?
alias :include? :has_key?

def []=(key, value)
load_for_write!
super(key.to_s, value)
@data[key.to_s] = value
end
alias :store :[]=

def clear
load_for_write!
super
@data.clear
end

def destroy
clear
options = @env[ENV_SESSION_OPTIONS_KEY]
options[:id] = @by.send(:destroy_session, @env, options[:id], options)
clear
@id = @by.send(:destroy_session, @env, id, options)
end

def to_hash
load_for_read!
Hash[self].delete_if { |k,v| v.nil? }
@data.dup
end

def update(hash)
load_for_write!
super(stringify_keys(hash))
@data.update(stringify_keys(hash))
end
alias :merge! :update

def replace(hash)
load_for_write!
@data.replace(stringify_keys(hash))
end

def delete(key)
load_for_write!
super(key.to_s)
@data.delete(key.to_s)
end

def inspect
if loaded?
super
@data.inspect
else
"#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
end
end

def exists?
return @exists if instance_variable_defined?(:@exists)
@data = {}
@exists = @by.send(:session_exists?, @env)
end

Expand All @@ -117,7 +114,7 @@ def loaded?

def empty?
load_for_read!
super
@data.empty?
end

def merge!(hash)
Expand All @@ -136,9 +133,8 @@ def load_for_write!
end

def load!
id, session = @by.send(:load_session, @env)
@env[ENV_SESSION_OPTIONS_KEY][:id] = id
replace(stringify_keys(session))
@id, session = @by.send(:load_session, @env)
@data = stringify_keys(session)
@loaded = true
end

Expand Down Expand Up @@ -243,7 +239,7 @@ def generate_sid(secure = @sid_secure)
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_OPTIONS_KEY] = @default_options.dup
env[ENV_SESSION_KEY].merge! session_was if session_was
end

Expand All @@ -268,7 +264,7 @@ def extract_session_id(env)
# Returns the current session id from the OptionsHash.

def current_session_id(env)
env[ENV_SESSION_OPTIONS_KEY][:id]
env[ENV_SESSION_KEY].id
end

# Check if the session exists or not.
Expand Down Expand Up @@ -314,21 +310,21 @@ def security_matches?(env, options)
# response with the session's id.

def commit_session(env, status, headers, body)
session = env['rack.session']
options = env['rack.session.options']
session = env[ENV_SESSION_KEY]
options = session.options

if options[:drop] || options[:renew]
session_id = destroy_session(env, options[:id] || generate_sid, options)
session_id = destroy_session(env, session.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
session_id ||= session.id || generate_sid
session_data = session.to_hash.delete_if { |k,v| v.nil? }

if not data = set_session(env, session_id, session, options)
if not data = set_session(env, session_id, session_data, 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
Expand Down

0 comments on commit 75b358c

Please sign in to comment.