/usr/lib/ruby/vendor_ruby/merb-core/dispatch/session/store_container.rb is in ruby-merb-core 1.1.3+dfsg-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | module Merb
class SessionStoreContainer < SessionContainer
class_inheritable_accessor :store
# :api: private
attr_accessor :_fingerprint
# Determines how many times to try generating a unique session key before we give up
GENERATE_MAX_TRIES = 100
# The class attribute :store holds a reference to an object that implements
# the following interface:
#
# - retrieve_session(session_id) # returns a Hash
# - store_session(session_id, data) # expects data to be Hash
# - delete_session(session_id)
#
# You can use session store classes directly by assigning to :store in your
# config/init.rb after_app_loads step, for example:
#
# Merb::BootLoader.after_app_loads do
# SessionStoreContainer.store = MemorySession.new
# end
#
# Or you can inherit from SessionStoreContainer to create a SessionContainer
# that delegates to aggregated store.
#
# class MemorySession < SessionStoreContainer
# self.session_store_type = :memory
# end
#
# class MemoryContainer
#
# def self.retrieve_session(session_id)
# ...
# end
#
# def self.store_session(session_id, data)
# ...
# end
#
# def self.delete_session(session_id)
# ...
# end
#
# end
# When used directly, report as :store store
self.session_store_type = :store
class << self
# Generates a new session ID and creates a new session.
#
# ==== Returns
# SessionStoreContainer:: The new session.
#
# :api: private
def generate
# make sure we generate a unique session uuid
sid = nil
GENERATE_MAX_TRIES.times do |i|
sid = Merb::SessionMixin.rand_uuid
data = store.retrieve_session(sid) rescue nil
break if data.nil?
raise "Unable to Generate Unique Session key" if i == (GENERATE_MAX_TRIES-1)
end
session = new(sid)
session.needs_new_cookie = true
session
end
# Setup a new session or retreive an existing session.
#
# ==== Parameters
# request<Merb::Request>:: The Merb::Request that came in from Rack.
#
# ==== Notes
# If no sessions were found, a new SessionContainer will be generated.
#
# ==== Returns
# SessionContainer:: a SessionContainer.
#
# :api: private
def setup(request)
session = retrieve(request.session_id)
request.session = session
# TODO Marshal.dump is slow - needs optimization
session._fingerprint = Marshal.dump(request.session.to_hash).hash
session
end
private
# ==== Parameters
# session_id<String:: The ID of the session to retrieve.
#
# ==== Returns
# SessionStoreContainer:: SessionStoreContainer instance with the session data. If no
# sessions matched session_id, a new SessionStoreContainer will be generated.
#
# ==== Notes
# If there are persisted exceptions callbacks to execute, they all get executed
# when Memcache library raises an exception.
#
# :api: private
def retrieve(session_id)
unless session_id.blank?
begin
session_data = store.retrieve_session(session_id)
rescue => err
Merb.logger.warn!("Could not retrieve session from #{self.name}: #{err.message}")
end
# Not in container, but assume that cookie exists
session_data = new(session_id) if session_data.nil?
else
# No cookie...make a new session_id
session_data = generate
end
if session_data.is_a?(self)
session_data
else
# Recreate using the existing session as the data, when switching
# from another session type for example, eg. cookie to memcached
# or when the data is just a hash
new(session_id).update(session_data)
end
end
end
# Teardown and/or persist the current session.
#
# If @_destroy is true, clear out the session completely, including
# removal of the session cookie itself.
#
# ==== Parameters
# request<Merb::Request>:: The Merb::Request that came in from Rack.
#
# ==== Notes
# The data (self) is converted to a Hash first, since a container might
# choose to do a full Marshal on the data, which would make it persist
# attributes like 'needs_new_cookie', which it shouldn't.
#
# :api: private
def finalize(request)
if @_destroy
store.delete_session(self.session_id)
request.destroy_session_cookie
else
if _fingerprint != Marshal.dump(data = self.to_hash).hash
begin
store.store_session(request.session(self.class.session_store_type).session_id, data)
rescue => err
Merb.logger.warn!("Could not persist session to #{self.class.name}: #{err.message}")
end
end
if needs_new_cookie || Merb::SessionMixin.needs_new_cookie?
request.set_session_id_cookie(self.session_id)
end
end
end
# Regenerate the session ID.
#
# :api: private
def regenerate
store.delete_session(self.session_id)
self.session_id = Merb::SessionMixin.rand_uuid
store.store_session(self.session_id, self)
end
end
end
|