1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/lib/cgi/session.rb

190 lines
3.7 KiB
Ruby
Raw Normal View History

# Copyright (C) 2001 Yukihiro "Matz" Matsumoto
# Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
# Copyright (C) 2000 Information-technology Promotion Agency, Japan
require 'cgi'
class CGI
class Session
attr_reader :session_id
def Session::callback(dbman)
lambda{
dbman[0].close unless dbman.empty?
}
end
def Session::create_new_id
require 'digest/md5'
md5 = Digest::MD5::new
md5.update(String(Time::now))
md5.update(String(rand(0)))
md5.update(String($$))
md5.update('foobar')
md5.hexdigest[0,16]
end
def initialize(request, option={})
session_key = option['session_key'] || '_session_id'
id, = option['session_id']
unless id
if option['new_session']
id = Session::create_new_id
end
end
unless id
id, = request[session_key]
id = id.read if id.respond_to?(:read)
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 = Session::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("name" => session_key,
"value" => id,
"expires" => option['session_expires'],
"domain" => option['session_domain'],
"secure" => option['session_secure'],
"path" => if option['session_path'] then
option['session_path']
elsif ENV["SCRIPT_NAME"] then
File::dirname(ENV["SCRIPT_NAME"])
else
""
end)
]
end
@dbprot = [@dbman]
ObjectSpace::define_finalizer(self, Session::callback(@dbprot))
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] = val
end
def update
@dbman.update
end
def close
@dbman.close
@dbprot.clear
end
def delete
@dbman.delete
@dbprot.clear
end
class FileStore
def check_id(id)
/[^0-9a-zA-Z]/ =~ id.to_s ? false : true
end
def initialize(session, option={})
dir = option['tmpdir'] || ENV['TMP'] || '/tmp'
prefix = option['prefix'] || ''
id = session.session_id
unless check_id(id)
raise ArgumentError, "session_id `%s' is invalid" % id
end
path = dir+"/"+prefix+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
return unless @hash
@f.rewind
for k,v in @hash
@f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v))
end
@f.truncate @f.tell
end
def close
return if @f.closed?
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=nil)
@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.delete(@session_id)
end
end
end
end