Thread: [Cgi-session-user] session data not being saved till flushed.
Brought to you by:
sherzodr
From: James.Q.L <shi...@ya...> - 2006-02-12 04:31:01
|
HI, I am using C::S 4.03 and the session data is not saved unless i call flush(). The doc claims otherwise, "Normally it will be called for you just before the program terminates, or session object goes out of scope, so you should never have to flush() on your own." Originally, I was using it with CGI::Application::Plugin::Session and noticed this behaviour. then I run this little test: % perl -MCGI::Session -e '$s=CGI::Session->new;$s->param("log",1)' % cat /tmp/cgisess_2c7678a377472c64a250304007295874 $D = {_SESSION_ID => '2c7678a377472c64a250304007295874',_SESSION_ATIME => 1139717550,log => 1,_SESSION_REMOTE_ADDR => '',_SESSION_CTIME => 1139717550}; % perl -MCGI::Session -e '$s=CGI::Session->new;$s->param("log",1);$s->flush()' % cat /tmp/cgisess_1d74dd15ded333689551116eae1ec263 $D = {_SESSION_ID => '1d74dd15ded333689551116eae1ec263',_SESSION_ATIME => 1139717605,log => 1,_SESSION_REMOTE_ADDR => '',_SESSION_CTIME => 1139717605}; looks like flush() call is necessary. James. __________________________________________________________ Find your next car at http://autos.yahoo.ca |
From: James.Q.L <shi...@ya...> - 2006-02-12 15:52:20
|
I tried another example and it worked (logged is flushed).. % perl -MCGI::Session -e '{my $s=CGI::Session->new();$s->param("logged",1)}' I am posting my code here and hopefully someone can spot why it doesn't flush in the login subroutine. another question along with the code: in the login sub, if user passes the authentication then calls session method which will create new session and send cookie(since i have SEND_COOKIE on), user will then be redirect to ./ . I am expecting a new cookie will be created when it is redirecting user to ./ but i don't see any cookie in the response header. therefor my script can't recognize the user as a logged in one. what's wrong in the code? ### Base.pm use base "CGI::Application"; sub cgiapp_init { my $self = shift; CGI::Session->name('S'); $self->session_config( CGI_SESSION_OPTIONS => [ "driver:File", $self->query, {Directory=>'/tmp/cgisession'} ], DEFAULT_EXPIRY => '+5m', COOKIE_PARAMS => { -domain => 'dev.example.com', -path => '/', }, SEND_COOKIE => 1, ); $self->dbh_config($self->config_param('sqlite.data_source')); } # Login.pm use base 'Base.pm'; sub setup { my $self = shift; $self->start_mode('show_form'); $self->run_modes('show_form' => 'show_form', 'login' => 'login', 'logout' => 'logout', ); $self->tmpl_path('Login/'); } sub show_form { my $self = shift; my %args = @_; my $query = $self->query(); my $tmpl = $self->load_tmpl('login.tmpl'); $tmpl->param(alert => $args{alert} || $query->param('alert')); return $tmpl->output(); } sub login { my $self = shift; my $query = $self->query(); my $username = $query->param('username'); my $password = $query->param('password'); return $self->show_form(alert => "User name and password are required fields.") unless defined $username and length $username and defined $password and length $password; # check username and password , my $user_id = $self->check_auth($username, $password); # failure return $self->show_form(alert => "Invalid login. The number of failed login attemps is $tries") unless $user_id; # update session if passed. my $session = $self->session; $session->param('_logged_in',1); $session->param('username',$username); # $session->flush(); # won't write to disk unless comment out this line $self->redirect_home; } ############ --- "James.Q.L" <shi...@ya...> wrote: > HI, > > I am using C::S 4.03 and the session data is not saved unless i call flush(). The doc claims > otherwise, "Normally it will be called for you just before the program terminates, or session > object goes out of scope, so you should never have to flush() on your own." > > Originally, I was using it with CGI::Application::Plugin::Session and noticed this behaviour. > then __________________________________________________________ Find your next car at http://autos.yahoo.ca |
From: Cees H. <ce...@gm...> - 2006-02-12 16:37:07
|
On 2/12/06, James.Q.L <shi...@ya...> wrote: > I tried another example and it worked (logged is flushed).. > % perl -MCGI::Session -e '{my $s=3DCGI::Session->new();$s->param("logged"= ,1)}' > > I am posting my code here and hopefully someone can spot why it doesn't f= lush in the login > subroutine. Nothing in the code you posted suggests any problems. So it must be somewhere else in the code. Do you by chance pass the $self->session object to your template? I believe that HTML::Template sometimes hangs on to the parameters that you send to it, and hence the Session object doesn't go out of scope (that is a wild guess btw) You can use Devel::Peek to double check the reference count of your variabl= es: perl -MDevel::Peek=3DDump -e 'my $x=3D10; Dump $x; my $y=3D\$x; Dump $x; Du= mp $y' Look at the value of REFCNT and how it changes when we store a reference to $x in $y. Since you are using CGI::Application, you can probably just setup a 'teardown' or 'cgiapp_postrun' method that looks at the REFCNT of the session object. ### UNTESTED CODE ### sub teardown { my $self =3D shift; my $session =3D $self->session; use Devel::Peek qw(Dump); print STDERR "Peeking at \$self->session\n----------\n"; Dump ($session); print STDERR "----------\n"; } Then check your error log and see the REFCNT value. If it is more than 2, then you have a problem somewhere in your code (there are already at least 2 copies, since $self has a copy, and you just made a fresh copy in $session). Although this might indicate that you have a problem, it doesn't give you any indication where the problem is in your code... > another question along with the code: in the login sub, if user passes th= e authentication then > calls session method which will create new session and send cookie(since = i have SEND_COOKIE on), > user will then be redirect to ./ . I am expecting a new cookie will be cr= eated when it is > redirecting user to ./ but i don't see any cookie in the response header.= therefor my script > can't recognize the user as a logged in one. what's wrong in the code? Try it again without the 'domain' and 'path' options to the cookie. I find that those two often keep cookies from being set correctly in the browser (actually, to be more acurate, they are set correctly in the browser, but the browser doesn't send them back on the next request).=20 You might also increase the expiry time while testing this. Also, make sure that the cookie is actually being sent to the browser in the first place (using something like the livehttpheaders plugin for mozilla makes this really easy). Cheers, Cees |
From: James.Q.L <shi...@ya...> - 2006-02-12 20:49:31
|
--- Cees Hek <ce...@gm...> wrote: > On 2/12/06, James.Q.L <shi...@ya...> wrote: > > I tried another example and it worked (logged is flushed).. > > % perl -MCGI::Session -e '{my $s=CGI::Session->new();$s->param("logged",1)}' > > > > I am posting my code here and hopefully someone can spot why it doesn't flush in the login > > subroutine. > > Nothing in the code you posted suggests any problems. So it must be > somewhere else in the code. Do you by chance pass the $self->session > object to your template? I believe that HTML::Template sometimes > hangs on to the parameters that you send to it, and hence the Session > object doesn't go out of scope (that is a wild guess btw) I do have $session object passed to HTML::Template as mentioned on CGI::Session tutorial. without editing that part, however, I tried my code again and session data is suddently all flushed without calling flush(). > > another question along with the code: in the login sub, if user passes the authentication then > > calls session method which will create new session and send cookie(since i have SEND_COOKIE > on), > > user will then be redirect to ./ . I am expecting a new cookie will be created when it is > > redirecting user to ./ but i don't see any cookie in the response header. therefor my script > > can't recognize the user as a logged in one. what's wrong in the code? > > Try it again without the 'domain' and 'path' options to the cookie. I > find that those two often keep cookies from being set correctly in the > browser (actually, to be more acurate, they are set correctly in the > browser, but the browser doesn't send them back on the next request). > You might also increase the expiry time while testing this. Also, > make sure that the cookie is actually being sent to the browser in the > first place (using something like the livehttpheaders plugin for > mozilla makes this really easy). I found out why the cookie doesn't sent during redirect. You see, i was using header_props for redirect which overrides the cookie header set in CPA::Session early on. that means header_props can't be used with CPA::Session and SEND_COOKIE is on. maybe this should be mentioned in CPA::Session doc? yes, I was using livehttpheader. now i find i need something to edit the cookie easily to test my script. the firefox extention "Add & Edit Cookies" looks promising, going to give it a go. > Cheers, > > Cees __________________________________________________________ Find your next car at http://autos.yahoo.ca |
From: Mark S. <ma...@su...> - 2006-02-13 01:31:26
|
On Sat, Feb 11, 2006 at 11:30:47PM -0500, James.Q.L wrote: > HI, > > I am using C::S 4.03 and the session data is not saved unless i call flush(). The doc claims > otherwise, "Normally it will be called for you just before the program terminates, or session > object goes out of scope, so you should never have to flush() on your own." Hello James, There are now several bug reports filed about related behavior, including one I filed myself just a few days ago: http://rt.cpan.org/Public/Bug/Display.html?id=17541 This much is clear: - For some people flush() used to happen automatically with 3.95, but quit working with 4.00 (and still isn't fixed in 4.03). - It's possible for third party modules to break the automatic flush() behavior, which I've confirmed myself. This can happen by creating a circular reference, so that the DESTROY method isn't invoked as expected. My proposal to address the situation is quit relying on flush() happen automatically, and recommend that people use an explicit flush() instead, which works reliably for everyone. That's what I'm doing. Actually, since I use CGI::Application, I just call flush() in teardown() and forget about it the rest of the time. This currently does have some overhead because it means that a session ma created at that moment so that flush() can be called on it! New functionality may be added to the Session plugin to address that. I have commit and release access for the CGI::Session project, but I wanted to get feedback from other people on the issue before proceeding. I know these flush() issues can be frustrating and time consuming to trackdown, so I'd like to address it soon. Mark |
From: James.Q.L <shi...@ya...> - 2006-02-13 14:24:51
|
--- Mark Stosberg <ma...@su...> wrote: > On Sat, Feb 11, 2006 at 11:30:47PM -0500, James.Q.L wrote: > > HI, > > > > I am using C::S 4.03 and the session data is not saved unless i call flush(). The doc claims > > otherwise, "Normally it will be called for you just before the program terminates, or session > > object goes out of scope, so you should never have to flush() on your own." > > Hello James, > > There are now several bug reports filed about related behavior, > including one I filed myself just a few days ago: > > http://rt.cpan.org/Public/Bug/Display.html?id=17541 > > This much is clear: > > - For some people flush() used to happen automatically with 3.95, but quit working > with 4.00 (and still isn't fixed in 4.03). > > - It's possible for third party modules to break the automatic flush() behavior, which > I've confirmed myself. This can happen by creating a circular reference, so that the > DESTROY method isn't invoked as expected. > > My proposal to address the situation is quit relying on flush() happen > automatically, and recommend that people use an explicit flush() > instead, which works reliably for everyone. > > That's what I'm doing. Actually, since I use CGI::Application, I just > call flush() in teardown() and forget about it the rest of the time. > This currently does have some overhead because it means that a session > ma created at that moment so that flush() can be called on it! how did CGI::Session handle the flush overhead before? thank you for the headsup and I am back to use flush(). > New functionality may be added to the Session plugin to address that. > > I have commit and release access for the CGI::Session project, but I > wanted to get feedback from other people on the issue before proceeding. > > I know these flush() issues can be frustrating and time consuming to > trackdown, so I'd like to address it soon. great! let me know if i can be any help. > Mark > James. __________________________________________________________ Find your next car at http://autos.yahoo.ca |
From: Mark S. <ma...@su...> - 2006-02-13 15:29:34
|
On Mon, Feb 13, 2006 at 09:24:40AM -0500, James.Q.L wrote: > > --- Mark Stosberg <ma...@su...> wrote: > > > On Sat, Feb 11, 2006 at 11:30:47PM -0500, James.Q.L wrote: > > > HI, > > > > > > I am using C::S 4.03 and the session data is not saved unless i call flush(). The doc claims > > > otherwise, "Normally it will be called for you just before the program terminates, or session > > > object goes out of scope, so you should never have to flush() on your own." > > > > Hello James, > > > > There are now several bug reports filed about related behavior, > > including one I filed myself just a few days ago: > > > > http://rt.cpan.org/Public/Bug/Display.html?id=17541 > > > > This much is clear: > > > > - For some people flush() used to happen automatically with 3.95, but quit working > > with 4.00 (and still isn't fixed in 4.03). > > > > - It's possible for third party modules to break the automatic flush() behavior, which > > I've confirmed myself. This can happen by creating a circular reference, so that the > > DESTROY method isn't invoked as expected. > > > > My proposal to address the situation is quit relying on flush() happen > > automatically, and recommend that people use an explicit flush() > > instead, which works reliably for everyone. > > > > That's what I'm doing. Actually, since I use CGI::Application, I just > > call flush() in teardown() and forget about it the rest of the time. > > This currently does have some overhead because it means that a session > > ma created at that moment so that flush() can be called on it! > > how did CGI::Session handle the flush overhead before? In the original design, there was no significant overhead. flush was called as part of DESTROY(), which happens when an object goes out of scope, and is not to be confused with an END{} block, which happens at the end of every request. flush() was only called on objects that were created, and only tried to update the storage backend if there was anything to flush. My suggestion for use with CGI::Application is more like the END{} block case, which happens at the end of every request. Since a session might not otherwise be created during a specific request, there's overhead in the possibility of a session being created for no real use. This is easily addressable by adding like "session_is_loaded()" method to CGI::Application::Plugin::Session. Then you can check to see if a session actually exists first, and only call flush() if there is one there. Mark |