2000-05-01 13:42:38 +04:00
|
|
|
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
|
|
|
# Copyright (C) 2000 Information-technology Promotion Agancy, Japan
|
1999-11-25 12:03:08 +03:00
|
|
|
|
1999-12-02 09:58:52 +03:00
|
|
|
require 'cgi'
|
1999-11-25 12:03:08 +03:00
|
|
|
require 'final'
|
|
|
|
|
|
|
|
class CGI
|
|
|
|
class Session
|
|
|
|
|
|
|
|
attr_reader :session_id
|
|
|
|
|
|
|
|
def Session::callback(dbman)
|
|
|
|
lambda{
|
|
|
|
dbman.close
|
|
|
|
}
|
|
|
|
end
|
|
|
|
|
|
|
|
def create_new_id
|
|
|
|
require 'md5'
|
|
|
|
md5 = MD5::new
|
|
|
|
md5.update(String(Time::now))
|
|
|
|
md5.update(String(rand(0)))
|
|
|
|
md5.update(String($$))
|
|
|
|
md5.update('foobar')
|
|
|
|
@session_id = md5.hexdigest[0,16]
|
|
|
|
end
|
|
|
|
private :create_new_id
|
|
|
|
|
|
|
|
def initialize(request, option={})
|
|
|
|
session_key = option['session_key'] || '_session_id'
|
|
|
|
id, = option['session_id']
|
|
|
|
unless id
|
|
|
|
if option['new_session']
|
|
|
|
id = create_new_id
|
|
|
|
end
|
|
|
|
end
|
|
|
|
unless id
|
|
|
|
id, = request[session_key]
|
|
|
|
unless id
|
|
|
|
id, = request.cookies[session_key]
|
|
|
|
end
|
|
|
|
unless id
|
|
|
|
if option.key?('new_session') and not option['new_session']
|
|
|
|
raise ArgumentError, "session_key `%s' should be supplied"%session_key
|
|
|
|
end
|
|
|
|
id = create_new_id
|
|
|
|
end
|
|
|
|
end
|
|
|
|
@session_id = id
|
|
|
|
dbman = option['database_manager'] || FileStore
|
|
|
|
@dbman = dbman::new(self, option)
|
|
|
|
request.instance_eval do
|
|
|
|
@output_hidden = {session_key => id}
|
|
|
|
@output_cookies = [Cookie::new(session_key,id)]
|
|
|
|
end
|
|
|
|
ObjectSpace::define_finalizer(self, Session::callback(@dbman))
|
|
|
|
end
|
|
|
|
|
|
|
|
def [](key)
|
|
|
|
unless @data
|
|
|
|
@data = @dbman.restore
|
|
|
|
end
|
|
|
|
@data[key]
|
|
|
|
end
|
|
|
|
|
|
|
|
def []=(key, val)
|
|
|
|
unless @write_lock
|
|
|
|
@write_lock = true
|
|
|
|
end
|
|
|
|
unless @data
|
|
|
|
@data = @dbman.restore
|
|
|
|
end
|
|
|
|
@data[key] = String(val)
|
|
|
|
end
|
|
|
|
|
|
|
|
def update
|
|
|
|
@dbman.update
|
|
|
|
end
|
|
|
|
|
|
|
|
def delete
|
|
|
|
@dbman.delete
|
|
|
|
end
|
|
|
|
|
|
|
|
class FileStore
|
|
|
|
def initialize(session, option={})
|
|
|
|
dir = option['tmpdir'] || ENV['TMP'] || '/tmp'
|
|
|
|
prefix = option['prefix'] || ''
|
|
|
|
path = dir+"/"+prefix+session.session_id
|
|
|
|
path.untaint
|
|
|
|
unless File::exist? path
|
|
|
|
@hash = {}
|
|
|
|
end
|
|
|
|
begin
|
|
|
|
@f = open(path, "r+")
|
|
|
|
rescue Errno::ENOENT
|
|
|
|
@f = open(path, "w+")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def restore
|
|
|
|
unless @hash
|
|
|
|
@hash = {}
|
|
|
|
@f.flock File::LOCK_EX
|
|
|
|
@f.rewind
|
|
|
|
for line in @f
|
|
|
|
line.chomp!
|
|
|
|
k, v = line.split('=',2)
|
|
|
|
@hash[CGI::unescape(k)] = CGI::unescape(v)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
@hash
|
|
|
|
end
|
|
|
|
|
|
|
|
def update
|
|
|
|
@f.rewind
|
|
|
|
for k,v in @hash
|
|
|
|
@f.printf "%s=%s\n", CGI::escape(k), CGI::escape(v)
|
|
|
|
end
|
|
|
|
@f.truncate @f.tell
|
|
|
|
end
|
|
|
|
|
|
|
|
def close
|
|
|
|
update
|
|
|
|
@f.close
|
|
|
|
end
|
|
|
|
|
|
|
|
def delete
|
|
|
|
path = @f.path
|
|
|
|
@f.close
|
|
|
|
File::unlink path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class MemoryStore
|
|
|
|
GLOBAL_HASH_TABLE = {}
|
|
|
|
|
|
|
|
def initialize(session, option={})
|
|
|
|
@session_id = session.session_id
|
|
|
|
GLOBAL_HASH_TABLE[@session_id] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
def restore
|
|
|
|
GLOBAL_HASH_TABLE[@session_id]
|
|
|
|
end
|
|
|
|
|
|
|
|
def update
|
|
|
|
# don't need to update; hash is shared
|
|
|
|
end
|
|
|
|
|
|
|
|
def close
|
|
|
|
# don't need to close
|
|
|
|
end
|
|
|
|
|
|
|
|
def delete
|
|
|
|
GLOBAL_HASH_TABLE[@session_id] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|