From 22a5aec4b322c1be9eced78967e5cfd0ae54b6cb Mon Sep 17 00:00:00 2001 From: wew Date: Fri, 29 Aug 2003 03:52:24 +0000 Subject: Add documentation in RDoc format. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@4455 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/cgi/session.rb | 282 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 278 insertions(+), 4 deletions(-) (limited to 'lib/cgi/session.rb') diff --git a/lib/cgi/session.rb b/lib/cgi/session.rb index 0ce82b3920..4ad6bf2a67 100644 --- a/lib/cgi/session.rb +++ b/lib/cgi/session.rb @@ -1,21 +1,175 @@ +# +# 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 + # The id of this session. attr_reader :session_id - def Session::callback(dbman) + def Session::callback(dbman) #:nodoc: lambda{ 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 Session::create_new_id require 'digest/md5' md5 = Digest::MD5::new @@ -26,6 +180,62 @@ class CGI md5.hexdigest[0,16] end + # 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 continue + # indefinitely. + # 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
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={}) session_key = option['session_key'] || '_session_id' id = option['session_id'] @@ -73,6 +283,7 @@ class CGI ObjectSpace::define_finalizer(self, Session::callback(@dbprot)) end + # Retrieve the session data for key +key+. def [](key) unless @data @data = @dbman.restore @@ -80,6 +291,7 @@ class CGI @data[key] end + # Set the session date for key +key+. def []=(key, val) unless @write_lock @write_lock = true @@ -90,25 +302,61 @@ class CGI @data[key] = val end - def update + # 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 - def check_id(id) + def check_id(id) #:nodoc: /[^0-9a-zA-Z]/ =~ id.to_s ? false : true end + # 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. + # + # 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'] || '' @@ -128,6 +376,9 @@ class CGI end end + # Restore session state from the session's FileStore file. + # + # Returns the session state as a hash. def restore unless @hash @hash = {} @@ -142,6 +393,7 @@ class CGI @hash end + # Save session state to the session's FileStore file. def update return unless @hash @f.rewind @@ -151,12 +403,14 @@ class CGI @f.truncate @f.tell end + # Update and close the session's FileStore file. def close return if @f.closed? update @f.close end + # Close and delete the session's FileStore file. def delete path = @f.path @f.close @@ -164,26 +418,46 @@ class CGI 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 = {} + 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 GLOBAL_HASH_TABLE[@session_id] ||= {} 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 -- cgit v1.2.3