Added 'httponly' to Cookie state options.
Tatsuhiko Miyagawa [Sat, 30 Jan 2010 09:36:13 +0000 (01:36 -0800)]
Support passing runtime configurations from psgix.session.options to
override domain, path, expires etc. from the apps.

lib/Plack/Session/State/Cookie.pm
t/014_cookie_options.t [new file with mode: 0644]
t/015_cookie_options_mw.t [new file with mode: 0644]

index 36639db..3ec6bb7 100644 (file)
@@ -14,6 +14,7 @@ use Plack::Util::Accessor qw[
     domain
     expires
     secure
+    httponly
 ];
 
 sub get_session_id {
@@ -21,14 +22,33 @@ sub get_session_id {
     Plack::Request->new($env)->cookies->{$self->session_key};
 }
 
+sub merge_options {
+    my($self, %options) = @_;
+
+    delete $options{id};
+
+    $options{path}     = $self->path || '/' if !exists $options{path} && defined $self->path;
+    $options{domain}   = $self->domain      if !exists $options{domain} && defined $self->domain;
+    $options{secure}   = $self->secure      if !exists $options{secure} && defined $self->secure;
+    $options{httponly} = $self->httponly    if !exists $options{httponly} && defined $self->httponly;
+
+    if (!exists $options{expires} && defined $self->expires) {
+        $options{expires} = time + $self->expires;
+    }
+
+    return %options;
+}
+
 sub expire_session_id {
     my ($self, $id, $res, $options) = @_;
-    $self->_set_cookie($id, $res, expires => time);
+    my %opts = $self->merge_options(%$options, expires => time);
+    $self->_set_cookie($id, $res, %opts);
 }
 
 sub finalize {
     my ($self, $id, $res, $options) = @_;
-    $self->_set_cookie($id, $res, (defined $self->expires ? (expires => time + $self->expires) : ()));
+    my %opts = $self->merge_options(%$options);
+    $self->_set_cookie($id, $res, %opts);
 }
 
 sub _set_cookie {
@@ -38,9 +58,6 @@ sub _set_cookie {
     my $response = Plack::Response->new($res);
     $response->cookies->{ $self->session_key } = +{
         value => $id,
-        path  => ($self->path || '/'),
-        ( defined $self->domain  ? ( domain  => $self->domain  ) : () ),
-        ( defined $self->secure  ? ( secure  => $self->secure  ) : () ),
         %options,
     };
 
diff --git a/t/014_cookie_options.t b/t/014_cookie_options.t
new file mode 100644 (file)
index 0000000..007ac96
--- /dev/null
@@ -0,0 +1,23 @@
+use strict;
+use Test::More;
+
+my $time = 1264843167;
+BEGIN { *CORE::GLOBAL::time = sub() { $time } }
+use Plack::Session::State::Cookie;
+
+my $st = Plack::Session::State::Cookie->new;
+$st->domain('.example.com');
+$st->secure(1);
+$st->expires(3600);
+$st->path('/cgi-bin');
+
+is_deeply +{ $st->merge_options(id => 123) },
+    { domain => '.example.com', secure => 1, expires => $time + 3600, path => '/cgi-bin' };
+
+is_deeply +{ $st->merge_options(id => 123, path => '/', domain => '.perl.org') },
+    { domain => '.perl.org', secure => 1, expires => $time + 3600, path => '/' };
+
+is_deeply +{ $st->merge_options(id => 123, expires => $time + 1, secure => 0) },
+    { domain => '.example.com', secure => 0, expires => $time + 1, path => '/cgi-bin' };
+
+done_testing;
diff --git a/t/015_cookie_options_mw.t b/t/015_cookie_options_mw.t
new file mode 100644 (file)
index 0000000..b373c46
--- /dev/null
@@ -0,0 +1,30 @@
+use strict;
+use Plack::Test;
+use Plack::Middleware::Session;
+use Test::More;
+use HTTP::Request::Common;
+use HTTP::Cookies;
+
+my $app = sub {
+    my $env = shift;
+
+    $env->{'psgix.session'}->{counter} = 1;
+
+    $env->{'psgix.session.options'}{path}     = '/foo';
+    $env->{'psgix.session.options'}{domain}   = '.example.com';
+    $env->{'psgix.session.options'}{httponly} = 1;
+
+    return [ 200, [], [ "Hi" ] ];
+};
+
+$app = Plack::Middleware::Session->wrap($app);
+
+test_psgi $app, sub {
+    my $cb = shift;
+
+    my $res = $cb->(GET "http://localhost/");
+    like $res->header('Set-Cookie'), qr/plack_session=\w+; domain=.example.com; path=\/foo; HttpOnly/;
+};
+
+done_testing;
+