diff options
author | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-07-07 07:38:25 +0000 |
---|---|---|
committer | shyouhei <shyouhei@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2008-07-07 07:38:25 +0000 |
commit | 9ff1e787f915539b1980654e3d3d2013ff5c81d2 (patch) | |
tree | 8d0fc9ca5b4dbfa9885dc56862292d55091bcaac /ruby_1_8_6/lib/cgi/session.rb | |
parent | 441546edcfbb1b346c87b69c5f578d1a0e522e06 (diff) |
wrong commit; sorryv1_8_6_269
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_8_6_269@17938 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ruby_1_8_6/lib/cgi/session.rb')
-rw-r--r-- | ruby_1_8_6/lib/cgi/session.rb | 492 |
1 files changed, 0 insertions, 492 deletions
diff --git a/ruby_1_8_6/lib/cgi/session.rb b/ruby_1_8_6/lib/cgi/session.rb deleted file mode 100644 index 5568b28dce..0000000000 --- a/ruby_1_8_6/lib/cgi/session.rb +++ /dev/null @@ -1,492 +0,0 @@ -# -# cgi/session.rb - session support for cgi scripts -# -# Copyright (C) 2001 Yukihiro "Matz" Matsumoto -# Copyright (C) 2000 Network Applied Communication Laboratory, Inc. -# Copyright (C) 2000 Information-technology Promotion Agency, Japan -# -# Author: Yukihiro "Matz" Matsumoto -# -# Documentation: William Webber (william@williamwebber.com) -# -# == Overview -# -# This file provides the +CGI::Session+ class, which provides session -# support for CGI scripts. A session is a sequence of HTTP requests -# and responses linked together and associated with a single client. -# Information associated with the session is stored -# on the server between requests. A session id is passed between client -# and server with every request and response, transparently -# to the user. This adds state information to the otherwise stateless -# HTTP request/response protocol. -# -# See the documentation to the +CGI::Session+ class for more details -# and examples of usage. See cgi.rb for the +CGI+ class itself. - -require 'cgi' -require 'tmpdir' - -class CGI - - # Class representing an HTTP session. See documentation for the file - # cgi/session.rb for an introduction to HTTP sessions. - # - # == Lifecycle - # - # A CGI::Session instance is created from a CGI object. By default, - # this CGI::Session instance will start a new session if none currently - # exists, or continue the current session for this client if one does - # exist. The +new_session+ option can be used to either always or - # never create a new session. See #new() for more details. - # - # #delete() deletes a session from session storage. It - # does not however remove the session id from the client. If the client - # makes another request with the same id, the effect will be to start - # a new session with the old session's id. - # - # == Setting and retrieving session data. - # - # The Session class associates data with a session as key-value pairs. - # This data can be set and retrieved by indexing the Session instance - # using '[]', much the same as hashes (although other hash methods - # are not supported). - # - # When session processing has been completed for a request, the - # session should be closed using the close() method. This will - # store the session's state to persistent storage. If you want - # to store the session's state to persistent storage without - # finishing session processing for this request, call the update() - # method. - # - # == Storing session state - # - # The caller can specify what form of storage to use for the session's - # data with the +database_manager+ option to CGI::Session::new. The - # following storage classes are provided as part of the standard library: - # - # CGI::Session::FileStore:: stores data as plain text in a flat file. Only - # works with String data. This is the default - # storage type. - # CGI::Session::MemoryStore:: stores data in an in-memory hash. The data - # only persists for as long as the current ruby - # interpreter instance does. - # CGI::Session::PStore:: stores data in Marshalled format. Provided by - # cgi/session/pstore.rb. Supports data of any type, - # and provides file-locking and transaction support. - # - # Custom storage types can also be created by defining a class with - # the following methods: - # - # new(session, options) - # restore # returns hash of session data. - # update - # close - # delete - # - # Changing storage type mid-session does not work. Note in particular - # that by default the FileStore and PStore session data files have the - # same name. If your application switches from one to the other without - # making sure that filenames will be different - # and clients still have old sessions lying around in cookies, then - # things will break nastily! - # - # == Maintaining the session id. - # - # Most session state is maintained on the server. However, a session - # id must be passed backwards and forwards between client and server - # to maintain a reference to this session state. - # - # The simplest way to do this is via cookies. The CGI::Session class - # provides transparent support for session id communication via cookies - # if the client has cookies enabled. - # - # If the client has cookies disabled, the session id must be included - # as a parameter of all requests sent by the client to the server. The - # CGI::Session class in conjunction with the CGI class will transparently - # add the session id as a hidden input field to all forms generated - # using the CGI#form() HTML generation method. No built-in support is - # provided for other mechanisms, such as URL re-writing. The caller is - # responsible for extracting the session id from the session_id - # attribute and manually encoding it in URLs and adding it as a hidden - # input to HTML forms created by other mechanisms. Also, session expiry - # is not automatically handled. - # - # == Examples of use - # - # === Setting the user's name - # - # require 'cgi' - # require 'cgi/session' - # require 'cgi/session/pstore' # provides CGI::Session::PStore - # - # cgi = CGI.new("html4") - # - # session = CGI::Session.new(cgi, - # 'database_manager' => CGI::Session::PStore, # use PStore - # 'session_key' => '_rb_sess_id', # custom session key - # 'session_expires' => Time.now + 30 * 60, # 30 minute timeout - # 'prefix' => 'pstore_sid_') # PStore option - # if cgi.has_key?('user_name') and cgi['user_name'] != '' - # # coerce to String: cgi[] returns the - # # string-like CGI::QueryExtension::Value - # session['user_name'] = cgi['user_name'].to_s - # elsif !session['user_name'] - # session['user_name'] = "guest" - # end - # session.close - # - # === Creating a new session safely - # - # require 'cgi' - # require 'cgi/session' - # - # cgi = CGI.new("html4") - # - # # We make sure to delete an old session if one exists, - # # not just to free resources, but to prevent the session - # # from being maliciously hijacked later on. - # begin - # session = CGI::Session.new(cgi, 'new_session' => false) - # session.delete - # rescue ArgumentError # if no old session - # end - # session = CGI::Session.new(cgi, 'new_session' => true) - # session.close - # - class Session - - class NoSession < RuntimeError #:nodoc: - end - - # The id of this session. - attr_reader :session_id, :new_session - - def Session::callback(dbman) #:nodoc: - Proc.new{ - dbman[0].close unless dbman.empty? - } - end - - # Create a new session id. - # - # The session id is an MD5 hash based upon the time, - # a random number, and a constant string. This routine - # is used internally for automatically generated - # session ids. - def create_new_id - require 'digest/md5' - md5 = Digest::MD5::new - now = Time::now - md5.update(now.to_s) - md5.update(String(now.usec)) - md5.update(String(rand(0))) - md5.update(String($$)) - md5.update('foobar') - @new_session = true - md5.hexdigest - end - private :create_new_id - - # Create a new CGI::Session object for +request+. - # - # +request+ is an instance of the +CGI+ class (see cgi.rb). - # +option+ is a hash of options for initialising this - # CGI::Session instance. The following options are - # recognised: - # - # session_key:: the parameter name used for the session id. - # Defaults to '_session_id'. - # session_id:: the session id to use. If not provided, then - # it is retrieved from the +session_key+ parameter - # of the request, or automatically generated for - # a new session. - # new_session:: if true, force creation of a new session. If not set, - # a new session is only created if none currently - # exists. If false, a new session is never created, - # and if none currently exists and the +session_id+ - # option is not set, an ArgumentError is raised. - # database_manager:: the name of the class providing storage facilities - # for session state persistence. Built-in support - # is provided for +FileStore+ (the default), - # +MemoryStore+, and +PStore+ (from - # cgi/session/pstore.rb). See the documentation for - # these classes for more details. - # - # The following options are also recognised, but only apply if the - # session id is stored in a cookie. - # - # session_expires:: the time the current session expires, as a - # +Time+ object. If not set, the session will terminate - # when the user's browser is closed. - # session_domain:: the hostname domain for which this session is valid. - # If not set, defaults to the hostname of the server. - # session_secure:: if +true+, this session will only work over HTTPS. - # session_path:: the path for which this session applies. Defaults - # to the directory of the CGI script. - # - # +option+ is also passed on to the session storage class initialiser; see - # the documentation for each session storage class for the options - # they support. - # - # The retrieved or created session is automatically added to +request+ - # as a cookie, and also to its +output_hidden+ table, which is used - # to add hidden input elements to forms. - # - # *WARNING* the +output_hidden+ - # fields are surrounded by a <fieldset> tag in HTML 4 generation, which - # is _not_ invisible on many browsers; you may wish to disable the - # use of fieldsets with code similar to the following - # (see http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/37805) - # - # cgi = CGI.new("html4") - # class << cgi - # undef_method :fieldset - # end - # - def initialize(request, option={}) - @new_session = false - session_key = option['session_key'] || '_session_id' - session_id = option['session_id'] - unless session_id - if option['new_session'] - session_id = create_new_id - end - end - unless session_id - if request.key?(session_key) - session_id = request[session_key] - session_id = session_id.read if session_id.respond_to?(:read) - end - unless session_id - session_id, = request.cookies[session_key] - end - unless session_id - unless option.fetch('new_session', true) - raise ArgumentError, "session_key `%s' should be supplied"%session_key - end - session_id = create_new_id - end - end - @session_id = session_id - dbman = option['database_manager'] || FileStore - begin - @dbman = dbman::new(self, option) - rescue NoSession - unless option.fetch('new_session', true) - raise ArgumentError, "invalid session_id `%s'"%session_id - end - session_id = @session_id = create_new_id - retry - end - request.instance_eval do - @output_hidden = {session_key => session_id} unless option['no_hidden'] - @output_cookies = [ - Cookie::new("name" => session_key, - "value" => session_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) - ] unless option['no_cookies'] - end - @dbprot = [@dbman] - ObjectSpace::define_finalizer(self, Session::callback(@dbprot)) - end - - # Retrieve the session data for key +key+. - def [](key) - @data ||= @dbman.restore - @data[key] - end - - # Set the session date for key +key+. - def []=(key, val) - @write_lock ||= true - @data ||= @dbman.restore - @data[key] = val - end - - # Store session data on the server. For some session storage types, - # this is a no-op. - def update - @dbman.update - end - - # Store session data on the server and close the session storage. - # For some session storage types, this is a no-op. - def close - @dbman.close - @dbprot.clear - end - - # Delete the session from storage. Also closes the storage. - # - # Note that the session's data is _not_ automatically deleted - # upon the session expiring. - def delete - @dbman.delete - @dbprot.clear - end - - # File-based session storage class. - # - # Implements session storage as a flat file of 'key=value' values. - # This storage type only works directly with String values; the - # user is responsible for converting other types to Strings when - # storing and from Strings when retrieving. - class FileStore - # Create a new FileStore instance. - # - # This constructor is used internally by CGI::Session. The - # user does not generally need to call it directly. - # - # +session+ is the session for which this instance is being - # created. The session id must only contain alphanumeric - # characters; automatically generated session ids observe - # this requirement. - # - # +option+ is a hash of options for the initialiser. The - # following options are recognised: - # - # tmpdir:: the directory to use for storing the FileStore - # file. Defaults to Dir::tmpdir (generally "/tmp" - # on Unix systems). - # prefix:: the prefix to add to the session id when generating - # the filename for this session's FileStore file. - # Defaults to the empty string. - # suffix:: the prefix to add to the session id when generating - # the filename for this session's FileStore file. - # Defaults to the empty string. - # - # This session's FileStore file will be created if it does - # not exist, or opened if it does. - def initialize(session, option={}) - dir = option['tmpdir'] || Dir::tmpdir - prefix = option['prefix'] || '' - suffix = option['suffix'] || '' - id = session.session_id - require 'digest/md5' - md5 = Digest::MD5.hexdigest(id)[0,16] - @path = dir+"/"+prefix+md5+suffix - if File::exist? @path - @hash = nil - else - unless session.new_session - raise CGI::Session::NoSession, "uninitialized session" - end - @hash = {} - end - end - - # Restore session state from the session's FileStore file. - # - # Returns the session state as a hash. - def restore - unless @hash - @hash = {} - begin - lockf = File.open(@path+".lock", "r") - lockf.flock File::LOCK_SH - f = File.open(@path, 'r') - for line in f - line.chomp! - k, v = line.split('=',2) - @hash[CGI::unescape(k)] = CGI::unescape(v) - end - ensure - f.close unless f.nil? - lockf.close if lockf - end - end - @hash - end - - # Save session state to the session's FileStore file. - def update - return unless @hash - begin - lockf = File.open(@path+".lock", File::CREAT|File::RDWR, 0600) - lockf.flock File::LOCK_EX - f = File.open(@path+".new", File::CREAT|File::TRUNC|File::WRONLY, 0600) - for k,v in @hash - f.printf "%s=%s\n", CGI::escape(k), CGI::escape(String(v)) - end - f.close - File.rename @path+".new", @path - ensure - f.close if f and !f.closed? - lockf.close if lockf - end - end - - # Update and close the session's FileStore file. - def close - update - end - - # Close and delete the session's FileStore file. - def delete - File::unlink @path+".lock" rescue nil - File::unlink @path+".new" rescue nil - File::unlink @path - rescue Errno::ENOENT - end - end - - # In-memory session storage class. - # - # Implements session storage as a global in-memory hash. Session - # data will only persist for as long as the ruby interpreter - # instance does. - class MemoryStore - GLOBAL_HASH_TABLE = {} #:nodoc: - - # Create a new MemoryStore instance. - # - # +session+ is the session this instance is associated with. - # +option+ is a list of initialisation options. None are - # currently recognised. - def initialize(session, option=nil) - @session_id = session.session_id - unless GLOBAL_HASH_TABLE.key?(@session_id) - unless session.new_session - raise CGI::Session::NoSession, "uninitialized session" - end - GLOBAL_HASH_TABLE[@session_id] = {} - end - end - - # Restore session state. - # - # Returns session data as a hash. - def restore - GLOBAL_HASH_TABLE[@session_id] - end - - # Update session state. - # - # A no-op. - def update - # don't need to update; hash is shared - end - - # Close session storage. - # - # A no-op. - def close - # don't need to close - end - - # Delete the session state. - def delete - GLOBAL_HASH_TABLE.delete(@session_id) - end - end - end -end |