views:

98

answers:

2

I'm using sessions in my Catalyst app via Session, Session::Store::DBIC, and Session::State::Cookie.

I have a few controllers and methods that send out data with a Cache-Control: public header, so its essential that the Set-Cookie: header not go out with those responses (otherwise, it'd be cached and sent to other clients, leading to possible security issues). I haven't found a good way to accomplish this.

How can I tell Session or Session::State::Cookie to not send a cookie in response to a given request?

A: 

Hi derobert,

It seems a bit unusual to approach it this way but I think I get what you are doing.

If I recall correctly, the Cookie State module simply sets the cookie in the response object:

$c->response->cookies

I don't think there's any magic there, and it only sets it to create or extend the session time. If you want to ensure that no cookies are sent. Clear out $c->response->cookies in Root end and you should be good to go.

JayK

jayk
If there is a better/more usual way to approach this, I'd love to hear it. This is my first real Catalyst app, so I may well be doing things in silly manners for no good reason.
derobert
`$c->log->debug("Cookies are: " . pp($c->response->cookies));` in my root's end logs cookies as being an empty hash already, and yet Set-Cookie is being sent anyway.
derobert
[info] *** Request 9 (1.125/s) [10894] [Mon Jul 27 11:20:48 2009] ***[debug] "GET" request for "js/tools/e3f84575109c4612819ae19e28973135" from "172.16.1.241"[debug] Path is "js"[debug] Arguments are "tools/e3f84575109c4612819ae19e28973135"[debug] Found sessionid "f356a9509668ea25f70b6b8dd2edef318dad95a1" in cookie[debug] Restored session "f356a9509668ea25f70b6b8dd2edef318dad95a1"[debug] Cookies are: {}[debug] Rendering template "js/tools.js"[debug] Passing page through as text: js/tools.js[info] Request took 0.110160s (9.078/s)
derobert
A: 

Doing a little RTFS, Session.pm overrides Catalyst's finalize_headers method and sets the cookie there, through a rather deep call chain:

finalize_header
⇒ _save_session_expires
⇒ session_expires
⇒ _extended_session_expires
⇒ extend_session_id (…::Session::State::Cookie)
⇒ update_session_cookie (…::Session::State::Cookie)

There does not appear to be any way to flag anything in the chain to stop. The only check is a method in Cookie.pm called cookie_is_rejecting which just compares the configured cookie path to the request path.

So, it looks like the best way to do this is to add my own override to either update_session_cookie or cookie_is_rejecting. I think I'll use cookie_is_rejecting.

Here is the code I finally used. Note that this is rather klugy, but it works...

package Catalyst::Plugin::Session::State::Cookie::Sanity;
use base qw/Catalyst::Plugin::Session::State::Cookie/;

use MRO::Compat;

use strict;

sub cookie_is_rejecting {
    my ($c, $cookie) = @_;

    ($c->stash->{cache_control_time} // 0) > 0
     or $c->maybe::next::method( $c, $cookie );
}

1;
derobert