File Coverage

blib/lib/HTTP/Session2/ServerStore.pm
Criterion Covered Total %
statement 87 87 100.0
branch 9 12 75.0
condition 6 6 100.0
subroutine 20 20 100.0
pod 0 7 0.0
total 122 132 92.4


line stmt bran cond sub pod time code
1             package HTTP::Session2::ServerStore;
2 2     2   38083 use strict;
  2         7  
  2         79  
3 2     2   12 use warnings;
  2         5  
  2         55  
4 2     2   10 use utf8;
  2         3  
  2         12  
5 2     2   106 use 5.008_001;
  2         8  
  2         433  
6              
7             our $VERSION = "1.09";
8              
9 2     2   23 use Carp ();
  2         4  
  2         47  
10 2     2   700 use Digest::HMAC;
  2         556  
  2         111  
11 2     2   879 use Digest::SHA ();
  2         4206  
  2         49  
12 2     2   710 use Cookie::Baker ();
  2         3954  
  2         54  
13 2     2   623 use HTTP::Session2::Expired;
  2         6  
  2         55  
14 2     2   643 use HTTP::Session2::Random;
  2         6  
  2         51  
15              
16 2     2   11 use Mouse;
  2         4  
  2         16  
17              
18             extends 'HTTP::Session2::Base';
19              
20             has store => (
21             is => 'ro',
22             required => 1,
23             lazy => 1,
24             default => sub {
25             unless (defined $_[0]->get_store) {
26             Carp::croak("store or get_store is required.");
27             }
28             $_[0]->get_store->()
29             },
30             );
31              
32             has get_store => (
33             is => 'ro',
34             isa => 'CodeRef',
35             required => 0,
36             );
37              
38             has xsrf_token => (
39             is => 'ro',
40             lazy => 1,
41             builder => '_build_xsrf_token',
42             );
43              
44 2     2   1086 no Mouse;
  2         4  
  2         15  
45              
46             sub load_session {
47 4     4 0 8 my $self = shift;
48              
49             # Load from cookie.
50 4         33 my $cookies = Cookie::Baker::crush_cookie($self->env->{HTTP_COOKIE});
51 4 100       145 if (my $session_id = $cookies->{$self->session_cookie->{name}}) {
52 3         21 my $data = $self->store->get($session_id);
53 3 50       65 if (defined $data) {
54 3         8 $self->{id} = $session_id;
55 3         6 $self->{_data} = $data;
56 3         11 return 1;
57             }
58             }
59             }
60              
61             sub create_session {
62 1     1 0 3 my $self = shift;
63              
64 1         5 $self->{id} = HTTP::Session2::Random::generate_session_id();
65 1         2 $self->{_data} = +{};
66 1         14 $self->is_fresh(1);
67             }
68              
69             sub regenerate_id {
70 1     1 0 427 my ($self) = @_;
71              
72             # Load original session first.
73 1         4 $self->load_session();
74              
75             # Remove original session from storage.
76 1         5 my $cookies = Cookie::Baker::crush_cookie($self->env->{HTTP_COOKIE});
77 1 50       28 if (my $session_id = $cookies->{$self->session_cookie->{name}}) {
78 1         5 $self->store->remove($session_id);
79             }
80              
81             # Clear XSRF token
82 1         6 delete $self->{xsrf_token};
83              
84             # Create new session.
85 1         4 $self->{id} = HTTP::Session2::Random::generate_session_id();
86 1         4 $self->necessary_to_send(1);
87 1         4 $self->is_dirty(1);
88             }
89              
90             sub expire {
91 1     1 0 685 my $self = shift;
92              
93             # Load original session first.
94             # # Is this needed?
95 1         4 $self->load_session();
96              
97             # Remove original session from storage.
98 1         6 my $cookies = Cookie::Baker::crush_cookie($self->env->{HTTP_COOKIE});
99 1 50       32 if (my $session_id = $cookies->{$self->session_cookie->{name}}) {
100 1         7 $self->store->remove($session_id);
101             }
102              
103             # Rebless to expired object.
104 1         11 bless $self, 'HTTP::Session2::Expired';
105              
106 1         4 return;
107             }
108              
109             sub _build_xsrf_token {
110 2     2   3 my $self = shift;
111              
112             # @kazuho san recommend to change this code as `hmax(secret, id, hmac_function)`.
113             # It makes secure. But we can't change this code for backward compatibility.
114             # We should change this code at HTTP::Session3.
115 2         7 Digest::HMAC::hmac_hex($self->id, $self->secret, $self->hmac_function);
116             }
117              
118             sub save_data {
119 4     4 0 7 my $self = shift;
120              
121 4 100       23 return unless $self->is_dirty;
122              
123 3         16 $self->store->set($self->id, $self->_data);
124             }
125              
126             sub finalize {
127 4     4 0 6 my $self = shift;
128 4         11 $self->save_data();
129 4         25 return $self->make_cookies();
130             }
131              
132             sub make_cookies {
133 4     4 0 7 my $self = shift;
134              
135 4 100 100     45 unless (
      100        
136             ($self->is_dirty && $self->is_fresh)
137             || $self->necessary_to_send
138             ) {
139 2         7 return ();
140             }
141              
142 2         6 my @cookies;
143              
144             # Finalize session cookie
145             {
146 2         3 my %cookie = %{$self->session_cookie};
  2         3  
  2         19  
147 2         4 my $name = delete $cookie{name};
148 2         8 push @cookies, $name => +{
149             %cookie,
150             value => $self->id,
151             };
152             }
153              
154             # Finalize XSRF cookie
155             {
156 2         2 my %cookie = %{$self->xsrf_cookie};
  2         5  
  2         14  
157 2         5 my $name = delete $cookie{name};
158 2         16 push @cookies, $name => +{
159             %cookie,
160             value => $self->xsrf_token,
161             };
162             }
163              
164 2         105 return @cookies;
165             }
166              
167             1;
168             __END__