dstar has asked for the wisdom of the Perl Monks concerning the following question:

I'm using mod_perl, Apache::Session, and Mason.

And it's not working. Specifically, sessions are not getting invalidated. I'm using the following code in my handler.pl file, taken from the article linked form masonhq:

# Get the incoming cookies my %cookies = parse CGI::Cookie($r->header_in('Cookie')); # Try to re-establish an existing session eval { tie %HTML::Mason::Commands::session, 'Apache::Session::DBI', ($cookies{'AF_SID'} ? $cookies{'AF_SID'}->value() : undef), { DataSource => $dbsource, UserName => $dbuser, Password => $dbpass }; }; # If we could not re-establish an existing # session, create a new session. if ( $@ ) { if ( $@ =~ m/^Object does not exist in the data store/ ) { tie %HTML::Mason::Commands::session, 'Apache::Session::DBI', undef, { DataSource => $dbsource, UserName => $dbuser, Password => $dbpass }; undef $cookies{'AF_SID'}; } } if ( !$cookies{'AF_SID'} ) { my $cookie = new CGI::Cookie(-name => 'AF_SID', -value => $HTML::Mason::Commands::session{_session_i +d}, -path => '/',); $r->header_out('Set-Cookie', => $cookie); } my $status = $ah->handle_request($r); untie %HTML::Mason::Commands::session; return $status;

The problem is it doesn't seem to be talking to the db -- once someone has sucessfully logged in on a particular child, $session{userid} *always* exists even if there's no corresponding row in the db sessions table.

I have to conclude there's something wrong with the way I'm doing it, but since I don't really *understand* how I'm doing it, I don't know what it is.

Replies are listed 'Best First'.
Re: Session Problems
by eejack (Hermit) on Aug 15, 2001 at 06:39 UTC
    I am pretty sure you need to put in the LockDataSource info as well. Below is a snippet from how I use Apache::Session ( I'm sorry but I am not familiar with Mason ).
    $dbtype = 'mysql'; $dbname = 'somedb'; $dbname = 'localhost'; $dbuser = 'username'; $dbpass = 'password'; tie %session, 'Apache::Session::MySQL', $id, { DataSource => "DBI:$dbtype:$dbname:$dbhost", UserName => $dbuser, Password => $dbpass, LockDataSource => "DBI:$dbtype:$dbname:$dbhost", LockUserName => $dbuser, LockPassword => $dbpass, } or die "Can't tie the session ", %session, ": $!";
    EEjack
      I can't find LockDataSource in Apache::Session::DBIStore anywhere. Is that a MySql specific thing?
        No, actually the Lock schtuff is in there to satisfy Apache::Session's need for a lock. I just don't grok the documentation on Apache::Session, so I found that just reading through the modules gave me better insight into getting it working, and it took a while.

        I didn't see a module Apache::Session::DBIStore, there is Apache::Session::Store::DBI, but that should be accessed through another module (like Apache::Session::Mysql or Apache::Session::Postgres ) as they also use the Apache::Session::Lock modules that are most appropriate.

        Or at least I think so, the docs are lacking in the explaining as far as I am concerned.

        EEjack

Re: Session Problems
by perrin (Chancellor) on Aug 15, 2001 at 17:57 UTC
    Are you saying the problem is just that $session is always there? This code is creating a new session if there isn't one already. You aren't setting $session{userid} anywhere in this code, so I don't know what you're doing with that or how you expected it to behave.

    One thing that I don't like about this code is how it doesn't always clean up if something goes wrong during handling the request. I think it would be better to put your session in $r->pnotes() than in a global, because pnotes is always cleaned up at the end of the request, even if Mason dies on something. If you haven't used pnotes before, see the docs that came with mod_perl or the Guide.

      $session{userid} *should* only exist if the person has a cookie from logging in. When they logout, $session{userid} is set to undef, and (as I understand it) the row in the DB is deleted. $session is a tied hash, so when someone connects they should get a new (empty) cookie if they don't have one; if they have one, then $session{userid} is whataver is stored in that.

      However, apparently doing $session{userid} = undef; *does* get rid of the info in the DB, but does not keep the child from remembering the value of $session{userid}.

      I don't know what's going on.

      dstar (forgot to log in)

        Okay, first off $session{userid} is not set anywhere in your sample code, and unless you're setting it somewhere else it will never get set to anything.

        Second, there is no concept of "loggin in" and "logging out" in this code. It assigns anyone who comes along a cookie with a session ID, and creates backend storage for that session. It never makes any attempt to delete anything from the database. Are you talking about some other code that you didn't post?

        There is a session ID, $session{_session_id}. Is that what you're talking about?

        Note that Apache::Session stores all data as a BLOB serialized by Storable, so removing a value from the session should not cause anything to be deleted from the database, it would just update the row for that session. Values are not stored as separate rows.

Re: Session Problems
by drfrog (Deacon) on Aug 15, 2001 at 19:24 UTC
    Hello

    im not familiar with mason either
    but i did take four hours a weekend ago to actually understand session
    here is a db enabled testscript
    you can run this like
    perl sessiontest.pl
    perl sessiontest.pl get_id=*sessionid*
    or
    perl sessiontest.pl visa_number=1234566

    first one set a session second grabs the session and
    third sets a session with the visa number
    #!/usr/bin/perl use strict; use Apache::Session::Postgres; use CGI; my $driver = "Pg"; my $dbname = "database"; my $host = "127.0.0.1"; my $user = "user"; my $password = "password"; my $dbh = DBI->connect( "dbi:$driver(PrintError=>1,RaiseError=>1,Taint=>1):dbname=$dbname;host +=$host", $user, $password ); my $q = CGI->new; my $id = $q->param('get_id'); my $visa_number = $q->param('visa_number'); tie my %hash, 'Apache::Session::Postgres', $id, { Handle => $dbh, }; if ( !$id && $visa_number ) { $hash{visa_number} = $visa_number; } use Data::Dumper; print Data::Dumper->Dump( [%hash] );
    back in the day we didnt have no old school
Found the problem, fixed, uncovered a *worse* one.
by dstar (Scribe) on Aug 16, 2001 at 05:46 UTC
    The problem was a typo when setting up the DB connection. Fixed that, started getting an error on line 143 of Apache::Session::DBIStore.

    So I added some code before the offending line:

    ### SDW DEBUG $self->{insert_sth}->trace(9, "/tmp/sessioncheck"); open(SDW_DEBUG_OUT, ">/tmp/serial"); print SDW_DEBUG_OUT "FOO".$serialized."BAR\n"; close(SDW_DEBUG_OUT);

    And I get:

    FOO bc6f80d5a358ae0f_session_idBAR

    Note the linefeed between FOO and the start of the sessionid. The serialized data seems to start with a linefeed! Needless to say, this foobars the sql statement.

    This can't be right, can it?