cvsuser     02/02/15 10:38:38

  Modified:    P5EEx/Blue/P5EEx/Blue Context.pm Session.pm
               P5EEx/Blue/P5EEx/Blue/Context HTML.pm
               P5EEx/Blue/P5EEx/Blue/Session HTMLHidden.pm
  Added:       P5EEx/Blue/P5EEx/Blue/Session Cookie.pm
  Log:
  Added cookie-based session maintenance
  
  Revision  Changes    Path
  1.14      +5 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Context.pm
  
  Index: Context.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Context.pm,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -w -r1.13 -r1.14
  --- Context.pm        8 Feb 2002 20:46:04 -0000       1.13
  +++ Context.pm        15 Feb 2002 18:38:37 -0000      1.14
  @@ -1,6 +1,6 @@
   
   #############################################################################
  -## $Id: Context.pm,v 1.13 2002/02/08 20:46:04 spadkins Exp $
  +## $Id: Context.pm,v 1.14 2002/02/15 18:38:37 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Context;
  @@ -209,6 +209,10 @@
   
       $self->{config} = P5EEx::Blue::P5EE->new($config_class, "new", \%args);
       $self->init(\%args);
  +
  +    $self->dbgprint("Context->new(): configClass=$config_class 
sessionClass=$session_class")
  +        if ($P5EEx::Blue::Context::DEBUG && $self->dbg(ref($self),"new",1));
  +
       $self->{session} = P5EEx::Blue::P5EE->new($session_class, "new", \%args);
       $self->{initconfig} = \%args;
   
  
  
  
  1.6       +5 -3      p5ee/P5EEx/Blue/P5EEx/Blue/Session.pm
  
  Index: Session.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Session.pm,v
  retrieving revision 1.5
  retrieving revision 1.6
  diff -u -w -r1.5 -r1.6
  --- Session.pm        5 Feb 2002 22:29:12 -0000       1.5
  +++ Session.pm        15 Feb 2002 18:38:37 -0000      1.6
  @@ -1,6 +1,6 @@
   
   #############################################################################
  -## $Id: Session.pm,v 1.5 2002/02/05 22:29:12 spadkins Exp $
  +## $Id: Session.pm,v 1.6 2002/02/15 18:38:37 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Session;
  @@ -75,11 +75,13 @@
   
   =item * Class: P5EEx::Blue::Session
   
  +=item * Class: P5EEx::Blue::Session::HTMLHidden
  +
  +=item * Class: P5EEx::Blue::Session::Cookie
  +
   =item * Class: P5EEx::Blue::Session::ApacheSession
   
   =item * Class: P5EEx::Blue::Session::ApacheSessionX
  -
  -=item * Class: P5EEx::Blue::Session::HTMLHidden
   
   =back
   
  
  
  
  1.5       +14 -3     p5ee/P5EEx/Blue/P5EEx/Blue/Context/HTML.pm
  
  Index: HTML.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Context/HTML.pm,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -w -r1.4 -r1.5
  --- HTML.pm   8 Feb 2002 20:47:19 -0000       1.4
  +++ HTML.pm   15 Feb 2002 18:38:38 -0000      1.5
  @@ -1,6 +1,6 @@
   
   #############################################################################
  -## $Id: HTML.pm,v 1.4 2002/02/08 20:47:19 spadkins Exp $
  +## $Id: HTML.pm,v 1.5 2002/02/15 18:38:38 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Context::HTML;
  @@ -188,8 +188,9 @@
   </html>
   EOF
   
  -    if ($main::target) {
  -        $header .= "Window-target: $main::target\n";
  +    if (defined $self->{headers}) {
  +        $header .= $self->{headers};
  +        delete $self->{headers}
       }
   
       if ($main::conf{gzip}) {
  @@ -279,6 +280,16 @@
       else {
           $self->dbgprint(ref($self), "->set_head_html(): $key=[repeat]")
               if ($P5EEx::Blue::Context::DEBUG >= 3 && $self->dbg(ref($self), 
"set_head_html", 3));
  +    }
  +}
  +
  +sub set_header {
  +    my ($self, $header) = @_;
  +    if (defined $self->{headers}) {
  +        $self->{headers} .= $header;
  +    }
  +    else {
  +        $self->{headers} = $header;
       }
   }
   
  
  
  
  1.4       +2 -1      p5ee/P5EEx/Blue/P5EEx/Blue/Session/HTMLHidden.pm
  
  Index: HTMLHidden.pm
  ===================================================================
  RCS file: /cvs/public/p5ee/P5EEx/Blue/P5EEx/Blue/Session/HTMLHidden.pm,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -w -r1.3 -r1.4
  --- HTMLHidden.pm     5 Feb 2002 22:25:58 -0000       1.3
  +++ HTMLHidden.pm     15 Feb 2002 18:38:38 -0000      1.4
  @@ -1,6 +1,6 @@
   
   #############################################################################
  -## $Id: HTMLHidden.pm,v 1.3 2002/02/05 22:25:58 spadkins Exp $
  +## $Id: HTMLHidden.pm,v 1.4 2002/02/15 18:38:38 spadkins Exp $
   #############################################################################
   
   package P5EEx::Blue::Session::HTMLHidden;
  @@ -276,6 +276,7 @@
               $state = thaw(Compress::Zlib::memGunzip(decode_base64($sessiontext)));
           }
       }
  +    $self->{context} = $args->{context} if (defined $args->{context});
       $self->{state} = $state;
       $self->{cache} = {};
   }
  
  
  
  1.1                  p5ee/P5EEx/Blue/P5EEx/Blue/Session/Cookie.pm
  
  Index: Cookie.pm
  ===================================================================
  
  #############################################################################
  ## $Id: Cookie.pm,v 1.1 2002/02/15 18:38:38 spadkins Exp $
  #############################################################################
  
  package P5EEx::Blue::Session::Cookie;
  
  use P5EEx::Blue::P5EE;
  use P5EEx::Blue::Session;
  @ISA = ( "P5EEx::Blue::Session" );
  
  use strict;
  
  use Data::Dumper;
  use Storable qw(freeze thaw);
  use Compress::Zlib;
  use MIME::Base64;
  
  # note: We may want to apply an HMAC (hashed message authentication code)
  #       so that users cannot fiddle with the values.
  #       We may also want to add IP address and timeout for security.
  #       We may also want to add encryption so they can't even decode the data.
  # use Digest::HMAC_MD5;
  # use Crypt::CBC;
  
  =head1 NAME
  
  P5EEx::Blue::Session::Cookie - a session whose state is maintained across
  HTML requests by being embedded in an HTML <input type="hidden"> tag.
  
  =head1 SYNOPSIS
  
     # ... official way to get a Session object ...
     use P5EEx::Blue::P5EE;
     $session = P5EEx::Blue::P5EE->session();
     $session = $session->session();   # get the session
  
     # any of the following named parameters may be specified
     $session = $session->session(
     );
  
     # ... alternative way (used internally) ...
     use P5EEx::Blue::Session::Cookie;
     $session = P5EEx::Blue::Session->new();
  
  =cut
  
  #############################################################################
  # CONSTANTS
  #############################################################################
  
  =head1 DESCRIPTION
  
  A Session class models the sequence of events associated with a
  use of the system.  These events may occur in different processes.
  Yet the accumulated state of the session needs to be propagated from
  one process to the next.
  
  This Session::Cookie maintains its state across
  HTML requests by being embedded in an HTTP cookie.
  As a result, it requires no server-side storage, so the sessions
  never need to time out.
  
  The Session::Cookie has an advantage over Session::HTMLHidden in that
  data does not need to be posted to a URL for the session data to be
  transmitted to it.  This allows that the state can be propagated
  properly to sub-components of an HTML page such as
  
   * frame documents within a frameset (<frame src=...>)
   * dynamically generated images (<img src=...>, <input type=image src=...>)
  
  Limits on cookie storage are as follows, according to "Dynamic HTML,
  The Definitive Reference" by O'Reilly in the DOM Reference under
  "document.cookie".
  
   * max 2000 chars per cookie (recommended, although 4000 supposedly allowed)
   * max 20 cookies per domain
   
  This allows for roughly 40K of session storage.
  It is quite conceivable that this amount of storage could be overrun,
  so Session::Cookie is only appropriate in situations where you are confident
  it will not be.  Also, widgets should take care to clean up after themselves,
  and static values stored in the session can alternatively be provided in
  the config.
  
  =cut
  
  #############################################################################
  # CONSTRUCTOR METHODS
  #############################################################################
  
  =head1 Constructor Methods:
  
  =cut
  
  #############################################################################
  # new()
  #############################################################################
  
  =head2 new()
  
  The constructor is inherited from
  L<C<P5EEx::Blue::Service>|P5EEx::Blue::Service/"new()">.
  
  =cut
  
  #############################################################################
  # PUBLIC METHODS
  #############################################################################
  
  =head1 Public Methods:
  
  =cut
  
  #############################################################################
  # get_session_id()
  #############################################################################
  
  =head2 get_session_id()
  
      * Signature: $session_id = $session->get_session_id();
      * Param:  void
      * Return: $session_id      string
      * Throws: <none>
      * Since:  0.01
  
      Sample Usage: 
  
      $session->get_session_id();
  
  The get_session_id() returns the session_id of this particular session.
  This session_id is unique for all time.  If a session_id does not yet
  exist, one will be created.  The session_id is only created when first
  requested, and not when the session is instantiated.
  
  =cut
  
  sub get_session_id {
      my $self = shift;
      "cookie";
  }
  
  #############################################################################
  # html()
  #############################################################################
  
  =head2 html()
  
  The html() method ...
  
      * Signature: $html = $session->html();
      * Param:  void
      * Return: $html      string
      * Throws: <none>
      * Since:  0.01
  
      Sample Usage: 
  
      $session->html();
  
  This method returns the empty string ("") as the HTML to be embedded in
  the page.  This is because a session_id does not need to be stored.
  However, it has the side effect that cookies are prepared for the HTTP
  response headers.
  
  =cut
  
  sub html {
      my ($self, $options) = @_;
      my ($sessiontext, $sessiondata, $html, $headers, $cookieoptions);
  
      $sessiondata = $self->{state};
      $sessiontext = encode_base64(Compress::Zlib::memGzip(freeze($sessiondata)));
  
      my ($maxvarsize, $maxvarlines);
      # length of a MIME/Base64 line is (76 chars + newline)
      # the max length of a cookie should be 2000 chars
      $maxvarlines = 25;
      $maxvarsize = $maxvarlines*77;  # 1925 chars
      $headers = "";
      $cookieoptions = ""; # TODO: expires, path, domain, secure
      $html = "";
  
      if (length($sessiontext) <= $maxvarsize) {
          $sessiontext =~ s/\n//g;  # get rid of newlines (76 char lines)
          $headers = "Set-Cookie: p5ee_sessiondata=$sessiontext$cookieoptions\n";
          $self->{context}->set_header($headers);
      }
      else {
          my (@sessiontext, $i, $startidx, $endidx, $textchunk);
          @sessiontext = split(/\n/,$sessiontext);
          $i = 1;
          $startidx = 0;
          $endidx = $startidx+$maxvarlines-1;
          $textchunk = join("",@sessiontext[$startidx .. $endidx]);
          $headers .= "Set-Cookie: p5ee_sessiondata=$textchunk$cookieoptions\n";
          while ($endidx < $#sessiontext) {
              $i++;
              $startidx += $maxvarlines;
              $endidx = $startidx+$maxvarlines-1;
              $endidx = $#sessiontext if ($endidx > $#sessiontext-1);
              $textchunk = join("",@sessiontext[$startidx .. $endidx]);
              $headers .= "Set-Cookie: 
p5ee_sessiondata${i}=$textchunk$cookieoptions\n";
          }
          $self->{context}->set_header($headers);
      }
  
      if ($options && $options->{showsession}) {
          # DEBUGGING ONLY
          my $d = Data::Dumper->new([ $sessiondata ], [ "sessiondata" ]);
          $d->Indent(1);
          $html .= "<!-- Contents of the session. (For debugging only. Should be 
turned off in production.)\n";
          $html .= $d->Dump();
          $html .= "-->\n";
      }
  
      $html;
  }
  
  #############################################################################
  # PROTECTED METHODS
  #############################################################################
  
  =head1 Protected Methods:
  
  The following methods are intended to be called by subclasses of the
  current class.
  
  =cut
  
  #############################################################################
  # create()
  #############################################################################
  
  =head2 create()
  
  The create() method is used to create the Perl structure that will
  be blessed into the class and returned by the constructor.
  
      * Signature: $ref = P5EEx::Blue::Reference->create($hashref)
      * Param:     $hashref            {}
      * Return:    $ref                ref
      * Throws:    P5EEx::Blue::Exception
      * Since:     0.01
  
      Sample Usage:
  
  =cut
  
  sub create {
      my ($self, $args) = @_;
      $args = {} if (!defined $args);
  
      my ($ref);
      $ref = {};
  
      $ref;
  }
  
  #############################################################################
  # init()
  #############################################################################
  
  =head2 init()
  
  The init() method is called from within the constructor.
  
      * Signature: init($named)
      * Param:     $named        {}    [in]
      * Return:    void
      * Throws:    P5EEx::Blue::Exception
      * Since:     0.01
  
      Sample Usage: 
  
      $ref->init($args);
  
  The init() method looks at the cookies in the request
  and restores the session state information from the cookies
  named "p5ee_sessiondata" (and "p5ee_sessiondata[2..n]").
  
  When the values of these cookies are concatenated, they
  form a Base64-encoded, gzipped, frozen multi-level hash of
  session state data.  To retrieve the state data, the text
  is therefore decoded, gunzipped, and thawed (a la Storable).
  
  TODO: encrypt and MAC
  
  =cut
  
  sub init {
      my ($self, $args) = @_;
      my ($cgi, $sessiontext, $state);
  
      $cgi = $args->{cgi} if (defined $args);
      $state = {};
      if (defined $cgi) {
          $sessiontext = $cgi->cookie("p5ee_sessiondata");
          if ($sessiontext) {
              my ($i, $textchunk);
              $i = 2;
              while (1) {
                  $textchunk = $cgi->cookie("p5ee_sessiondata${i}");
                  last if (!$textchunk);
                  $sessiontext .= $textchunk;
                  $i++;
              }
              $sessiontext =~ s/(.{76})/$1\n/g;
              $sessiontext .= "\n";
              $state = thaw(Compress::Zlib::memGunzip(decode_base64($sessiontext)));
          }
      }
      $self->{context} = $args->{context} if (defined $args->{context});
      $self->{state} = $state;
      $self->{cache} = {};
  }
  
  1;
  
  
  
  


Reply via email to