From: ahoward Date: 2003-05-30T13:26:15+09:00 Subject: Re: [Q]: CGI::Session On Fri, 30 May 2003, Tom Danielsen wrote: > I created a MarshaledFileStore class (slightly modified FileStore), > but it won't work for some mysterious reason : i did something similar a while back - i've used in many cgi programs and it works great http://raa.ruby-lang.org/list.rhtml?name=cgi-sess-pstore -a > > [Sat May 31 03:26:37 2003] [error] mod_ruby: error in ruby > /usr/local/lib/ruby/1.8/cgi/session.rb:155:in `dump': singleton can't be dumped (TypeError) > from /usr/local/lib/ruby/1.8/cgi/session.rb:155:in `update' > from /usr/local/lib/ruby/1.8/cgi/session.rb:161:in `close' > from /usr/local/lib/ruby/1.8/cgi/session.rb:96:in `close' > from /www/htdocs/app1.rbx:45 > from /usr/local/lib/ruby/1.8/apache/ruby-run.rb:70:in `load' > from /usr/local/lib/ruby/1.8/apache/ruby-run.rb:70:in `handler' > > This is what the hash looks like (output from my modified session.rb) : > > /www% more /tmp/h.h > class of @hash is 'Hash' > {"name"=>"test", "visited"=>8} > 'name' (String) => 'test' (String) > 'visited' (String) => '8' (Fixnum) > /www% > > So......singleton ?? > > And here is the modified session.rb : > > regards, > Tom > > > ------------- cut ------------- > # 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') > ### TOM md5.hexdigest[0,16] > md5.hexdigest > 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 MarshaledFileStore > 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 > @hash = Marshal.load(@f) > end > @hash > end > > def update > return unless @hash > @f.rewind > File.open("/tmp/h.h","w+") { |f| > f.print "class of @hash is '#{@hash.class.to_s}'\n" > f.print @hash.inspect + "\n" > @hash.each { |k,v| > f.print "'#{k.to_s}' (#{k.class.to_s}) => '#{v.to_s}' (#{v.class.to_s})\n" > } > } > Marshal.dump(@hash, @f) > @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 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 > > > > > -a -- ==================================== | Ara Howard | NOAA Forecast Systems Laboratory | Information and Technology Services | Data Systems Group | R/FST 325 Broadway | Boulder, CO 80305-3328 | Email: ara.t.howard@fsl.noaa.gov | Phone: 303-497-7238 | Fax: 303-497-7259 | ~ > ruby -e 'p % ^) .intern' ====================================