2001-01-09 02:26:21 -05:00
|
|
|
# Copyright (C) 2001 Yukihiro "Matz" Matsumoto
|
2000-05-01 05:42:38 -04:00
|
|
|
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
|
2000-05-09 00:53:16 -04:00
|
|
|
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
|
1999-11-25 04:03:08 -05:00
|
|
|
|
1999-12-02 01:58:52 -05:00
|
|
|
require 'cgi'
|
1999-11-25 04:03:08 -05:00
|
|
|
|
|
|
|
class CGI
|
|
|
|
class Session
|
|
|
|
|
|
|
|
attr_reader :session_id
|
|
|
|
|
|
|
|
def Session::callback(dbman)
|
|
|
|
lambda{
|
2001-08-05 23:05:23 -04:00
|
|
|
dbman[0].close unless dbman.empty?
|
1999-11-25 04:03:08 -05:00
|
|
|
}
|
|
|
|
end
|
|
|
|
|
2001-01-09 02:26:21 -05:00
|
|
|
def Session::create_new_id
|
2001-12-01 09:07:01 -05:00
|
|
|
require 'digest/md5'
|
|
|
|
md5 = Digest::MD5::new
|
1999-11-25 04:03:08 -05:00
|
|
|
md5.update(String(Time::now))
|
|
|
|
md5.update(String(rand(0)))
|
|
|
|
md5.update(String($$))
|
|
|
|
md5.update('foobar')
|
2001-01-09 02:26:21 -05:00
|
|
|
md5.hexdigest[0,16]
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def initialize(request, option={})
|
|
|
|
session_key = option['session_key'] || '_session_id'
|
|
|
|
id, = option['session_id']
|
|
|
|
unless id
|
|
|
|
if option['new_session']
|
2001-01-09 02:26:21 -05:00
|
|
|
id = Session::create_new_id
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
unless id
|
|
|
|
id, = request[session_key]
|
2002-04-10 13:02:47 -04:00
|
|
|
id = id.read if id.respond_to?(:read)
|
1999-11-25 04:03:08 -05:00
|
|
|
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
|
2001-01-09 02:26:21 -05:00
|
|
|
id = Session::create_new_id
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
@session_id = id
|
|
|
|
dbman = option['database_manager'] || FileStore
|
|
|
|
@dbman = dbman::new(self, option)
|
|
|
|
request.instance_eval do
|
|
|
|
@output_hidden = {session_key => id}
|
2000-09-07 02:59:46 -04:00
|
|
|
@output_cookies = [
|
2000-10-17 14:14:05 -04:00
|
|
|
Cookie::new("name" => session_key,
|
|
|
|
"value" => id,
|
2002-08-19 01:56:09 -04:00
|
|
|
"expires" => option['session_expires'],
|
|
|
|
"domain" => option['session_domain'],
|
|
|
|
"secure" => option['session_secure'],
|
2001-01-09 02:26:21 -05:00
|
|
|
"path" => if option['session_path'] then
|
|
|
|
option['session_path']
|
|
|
|
elsif ENV["SCRIPT_NAME"] then
|
2000-09-07 02:59:46 -04:00
|
|
|
File::dirname(ENV["SCRIPT_NAME"])
|
|
|
|
else
|
|
|
|
""
|
|
|
|
end)
|
|
|
|
]
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
2001-08-05 23:05:23 -04:00
|
|
|
@dbprot = [@dbman]
|
|
|
|
ObjectSpace::define_finalizer(self, Session::callback(@dbprot))
|
1999-11-25 04:03:08 -05:00
|
|
|
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
|
2001-11-13 03:14:27 -05:00
|
|
|
@data[key] = val
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
def update
|
|
|
|
@dbman.update
|
|
|
|
end
|
|
|
|
|
2000-10-17 14:14:05 -04:00
|
|
|
def close
|
|
|
|
@dbman.close
|
2001-08-05 23:05:23 -04:00
|
|
|
@dbprot.clear
|
2000-10-17 14:14:05 -04:00
|
|
|
end
|
|
|
|
|
1999-11-25 04:03:08 -05:00
|
|
|
def delete
|
|
|
|
@dbman.delete
|
2001-08-05 23:05:23 -04:00
|
|
|
@dbprot.clear
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
class FileStore
|
2001-05-06 11:06:00 -04:00
|
|
|
def check_id(id)
|
|
|
|
/[^0-9a-zA-Z]/ =~ id.to_s ? false : true
|
|
|
|
end
|
|
|
|
|
1999-11-25 04:03:08 -05:00
|
|
|
def initialize(session, option={})
|
|
|
|
dir = option['tmpdir'] || ENV['TMP'] || '/tmp'
|
|
|
|
prefix = option['prefix'] || ''
|
2001-05-06 11:06:00 -04:00
|
|
|
id = session.session_id
|
|
|
|
unless check_id(id)
|
|
|
|
raise ArgumentError, "session_id `%s' is invalid" % id
|
|
|
|
end
|
|
|
|
path = dir+"/"+prefix+id
|
1999-11-25 04:03:08 -05:00
|
|
|
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
|
2002-04-10 04:45:26 -04:00
|
|
|
return unless @hash
|
1999-11-25 04:03:08 -05:00
|
|
|
@f.rewind
|
|
|
|
for k,v in @hash
|
2001-11-13 03:14:27 -05:00
|
|
|
@f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v))
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
@f.truncate @f.tell
|
|
|
|
end
|
|
|
|
|
|
|
|
def close
|
2001-02-14 21:45:09 -05:00
|
|
|
return if @f.closed?
|
1999-11-25 04:03:08 -05:00
|
|
|
update
|
|
|
|
@f.close
|
|
|
|
end
|
|
|
|
|
|
|
|
def delete
|
|
|
|
path = @f.path
|
|
|
|
@f.close
|
|
|
|
File::unlink path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class MemoryStore
|
|
|
|
GLOBAL_HASH_TABLE = {}
|
|
|
|
|
2001-05-06 11:06:00 -04:00
|
|
|
def initialize(session, option=nil)
|
1999-11-25 04:03:08 -05:00
|
|
|
@session_id = session.session_id
|
2001-05-06 11:06:00 -04:00
|
|
|
GLOBAL_HASH_TABLE[@session_id] ||= {}
|
1999-11-25 04:03:08 -05:00
|
|
|
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
|
2001-05-06 11:06:00 -04:00
|
|
|
GLOBAL_HASH_TABLE.delete(@session_id)
|
1999-11-25 04:03:08 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|