File Coverage

blib/lib/HTTP/Session2/ServerStore.pm
Criterion Covered Total %
statement 87 87 100.0
branch 11 14 78.5
condition 8 9 88.8
subroutine 20 20 100.0
pod 0 7 0.0
total 126 137 91.9


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