File Coverage

blib/lib/HTTP/Session2/Base.pm
Criterion Covered Total %
statement 61 61 100.0
branch 12 12 100.0
condition n/a
subroutine 20 20 100.0
pod 5 11 45.4
total 98 104 94.2


line stmt bran cond sub pod time code
1             package HTTP::Session2::Base;
2 13     13   57600 use strict;
  13         32  
  13         282  
3 13     13   46 use warnings;
  13         21  
  13         232  
4 13     13   498 use utf8;
  13         29  
  13         45  
5 13     13   330 use 5.008_001;
  13         34  
6              
7 13     13   3066 use Digest::SHA;
  13         16891  
  13         488  
8 13     13   64 use Carp ();
  13         25  
  13         226  
9              
10 13     13   4801 use Mouse;
  13         288224  
  13         97  
11              
12             has env => (
13             is => 'ro',
14             required => 1,
15             );
16              
17             has session_cookie => (
18             is => 'ro',
19             lazy => 1,
20             default => sub {
21             +{
22             httponly => 1,
23             secure => 0,
24             name => 'hss_session',
25             path => '/',
26             },
27             },
28             # Need shallow copy
29             trigger => sub {
30             my $self = shift;
31             $self->{session_cookie} = +{%{$self->{session_cookie}}};
32             },
33             );
34              
35             has xsrf_cookie => (
36             is => 'ro',
37             lazy => 1,
38             default => sub {
39             # httponly must be false. AngularJS need to read this value.
40             +{
41             httponly => 0,
42             secure => 0,
43             name => 'XSRF-TOKEN',
44             path => '/',
45             },
46             },
47             # Need shallow copy
48             trigger => sub {
49             my $self = shift;
50             $self->{xsrf_cookie} = +{%{$self->{xsrf_cookie}}};
51             },
52             );
53              
54             has hmac_function => (
55             is => 'ro',
56             default => sub { \&Digest::SHA::sha1_hex },
57             );
58              
59             has is_dirty => (
60             is => 'rw',
61             default => sub { 0 },
62             );
63              
64             has is_fresh => (
65             is => 'rw',
66             default => sub { 0 },
67             );
68              
69             has necessary_to_send => (
70             is => 'rw',
71             default => sub { 0 },
72             );
73              
74             has secret => (
75             is => 'ro',
76             required => 1,
77             trigger => sub {
78             my ($self, $secret) = @_;
79             if (length($secret) < 20) {
80             Carp::cluck("Secret string too short");
81             }
82             },
83             );
84              
85 13     13   7806 no Mouse;
  13         76  
  13         55  
86              
87             sub _data {
88 95     95   161 my $self = shift;
89 95 100       220 unless ($self->{_data}) {
90 23         76 $self->load_or_create();
91             }
92 95         244 $self->{_data};
93             }
94              
95             sub id {
96 92     92 0 12295 my $self = shift;
97 92 100       212 unless ($self->{id}) {
98 26         60 $self->load_or_create();
99             }
100 92         400 $self->{id};
101             }
102              
103             sub load_or_create {
104 49     49 0 72 my $self = shift;
105 49 100       144 $self->load_session() || $self->create_session();
106             }
107              
108 1     1 0 86 sub load_session { die "Abstract method" }
109 1     1 0 599 sub create_session { die "Abstract method" }
110              
111             sub set {
112 27     27 1 5560 my ($self, $key, $value) = @_;
113 27         101 $self->_data->{$key} = $value;
114 27         108 $self->is_dirty(1);
115             }
116              
117             sub get {
118 25     25 1 998 my ($self, $key) = @_;
119 25         72 $self->_data->{$key};
120             }
121              
122             sub remove {
123 1     1 1 3 my ($self, $key) = @_;
124 1         3 $self->is_dirty(1);
125 1         2 delete $self->_data->{$key};
126             }
127              
128             sub validate_xsrf_token {
129 16     16 1 740 my ($self, $token) = @_;
130              
131             # If user does not have any session data, user don't need a XSRF protection.
132 16 100       21 return 1 unless %{$self->_data};
  16         34  
133 14 100       35 return 0 unless defined $token;
134 12 100       50 return 1 if $token eq $self->xsrf_token;
135 3         29 return 0;
136             }
137              
138             sub finalize_plack_response {
139 2     2 1 75 my ($self, $res) = @_;
140              
141 2         7 my @cookies = $self->finalize();
142 2         9 while (my ($name, $cookie) = splice @cookies, 0, 2) {
143 4         109 my $baked = Cookie::Baker::bake_cookie( $name, $cookie );
144 4         225 $res->headers->push_header('Set-Cookie' => $baked);
145             }
146             }
147              
148             sub finalize_psgi_response {
149 47     47 0 5865 my ($self, $res) = @_;
150 47         134 my @cookies = $self->finalize();
151 47         176 while (my ($name, $cookie) = splice @cookies, 0, 2) {
152 54         144 my $baked = Cookie::Baker::bake_cookie( $name, $cookie );
153 54         2309 push @{$res->[1]}, (
  54         275  
154             'Set-Cookie' => $baked,
155             );
156             }
157             }
158              
159 1     1 0 475 sub finalize { die "Abstract method" }
160              
161             1;
162             __END__