File Coverage

blib/lib/Dancer/Cookie.pm
Criterion Covered Total %
statement 66 69 95.6
branch 36 40 90.0
condition 3 3 100.0
subroutine 10 10 100.0
pod 3 3 100.0
total 118 125 94.4


line stmt bran cond sub pod time code
1             package Dancer::Cookie;
2             our $AUTHORITY = 'cpan:SUKRIA';
3             #ABSTRACT: class representing cookies
4             $Dancer::Cookie::VERSION = '1.3514_04'; # TRIAL
5             $Dancer::Cookie::VERSION = '1.351404';
6 189     189   164550 use strict;
  189         350  
  189         4514  
7 189     189   815 use warnings;
  189         317  
  189         3770  
8              
9 189     189   765 use Carp;
  189         320  
  189         8790  
10 189     189   67178 use URI::Escape;
  189         234290  
  189         10301  
11              
12 189     189   1284 use base 'Dancer::Object';
  189         359  
  189         197102  
13             __PACKAGE__->attributes( qw/name expires domain path same_site secure http_only/ );
14              
15             sub init {
16 88     88 1 254 my ($self, %args) = @_;
17 88         287 $self->value($args{value});
18 88 100       254 if (my $time = $self->expires) {
19             # First, normalize things like +2h to # of seconds
20 16 100       82 $time = _parse_duration($time) if $time !~ /^\d+$/;
21              
22             # Then translate to a gmt string, if it isn't one already
23 16 100       78 $time = _epoch_to_gmtstring($time) if $time =~ /^\d+$/;
24              
25 16         36 $self->expires($time);
26             }
27 88 100       253 $self->path('/') unless defined $self->path;
28              
29             # If we have a same_site attribute, ensure it's sane:
30 88 100       242 if (my $same_site = $self->same_site) {
31 35 50       315 if ($same_site !~ m{^(Strict|Lax|None)$}i) {
32 0         0 Carp::croak(
33             "Invalid same_site value '$same_site'"
34             . " - must be 'Strict', 'Lax' or 'None', see RFC6265bis"
35             );
36             } else {
37             # Normalise case
38 35         184 $self->same_site(ucfirst lc $same_site);
39             }
40             }
41             }
42              
43             sub to_header {
44 37     37 1 1918 my $self = shift;
45 37         67 my $header = '';
46              
47 37         77 my $value = join('&', map {uri_escape($_)} $self->value);
  40         150  
48 37   100     786 my $no_httponly = defined( $self->http_only ) && $self->http_only == 0;
49              
50 37         96 my $name = $self->name;
51 37         90 $name =~ s/[=,; \t\r\n\013\014]//mg;
52              
53 37         111 my @headers = $name . '=' . $value;
54 37 50       97 push @headers, "path=" . $self->path if $self->path;
55 37 100       92 push @headers, "expires=" . $self->expires if $self->expires;
56 37 100       92 push @headers, "domain=" . $self->domain if $self->domain;
57 37 100       108 push @headers, "Secure" if $self->secure;
58 37 100       105 push @headers, "SameSite=" . $self->same_site if $self->same_site;
59 37 100       90 push @headers, 'HttpOnly' unless $no_httponly;
60              
61 37         166 return join '; ', @headers;
62             }
63              
64             sub value {
65 484     484 1 744 my ( $self, $value ) = @_;
66 484 100       833 if ( defined $value ) {
67 88 100       361 my @values =
    100          
68             ref $value eq 'ARRAY' ? @$value
69             : ref $value eq 'HASH' ? %$value
70             : ($value);
71 88         299 $self->{'value'} = [@values];
72             }
73 484 100       1208 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  181         683  
74             }
75              
76             sub _epoch_to_gmtstring {
77 14     14   23 my ($epoch) = @_;
78              
79 14         79 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($epoch);
80 14         46 my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
81 14         23 my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
82              
83 14         82 return sprintf "%s, %02d-%s-%d %02d:%02d:%02d GMT",
84             $days[$wday],
85             $mday,
86             $months[$mon],
87             ($year + 1900),
88             $hour, $min, $sec;
89             }
90              
91             # This map is taken from Cache and Cache::Cache
92             # map of expiration formats to their respective time in seconds
93             my %Units = ( map(($_, 1), qw(s second seconds sec secs)),
94             map(($_, 60), qw(m minute minutes min mins)),
95             map(($_, 60*60), qw(h hr hour hours)),
96             map(($_, 60*60*24), qw(d day days)),
97             map(($_, 60*60*24*7), qw(w week weeks)),
98             map(($_, 60*60*24*30), qw(M month months)),
99             map(($_, 60*60*24*365), qw(y year years)) );
100              
101             # This code is taken from Time::Duration::Parse, except if it isn't
102             # understood it just passes it through and it adds the current time.
103             sub _parse_duration {
104 8     8   16 my $timespec = shift;
105 8         12 my $orig_timespec = $timespec;
106              
107             # Treat a plain number as a number of seconds (and parse it later)
108 8 50       38 if ($timespec =~ /^\s*([-+]?\d+(?:[.,]\d+)?)\s*$/) {
109 0         0 $timespec = "$1s";
110             }
111              
112             # Convert hh:mm(:ss)? to something we understand
113 8         38 $timespec =~ s/\b(\d+):(\d\d):(\d\d)\b/$1h $2m $3s/g;
114 8         12 $timespec =~ s/\b(\d+):(\d\d)\b/$1h $2m/g;
115              
116 8         12 my $duration = 0;
117 8         43 while ($timespec =~ s/^\s*([-+]?\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)(?:\s*(?:,|and)\s*)*//i) {
118 10         29 my($amount, $unit) = ($1, $2);
119 10 100       24 $unit = lc($unit) unless length($unit) == 1;
120              
121 10 50       23 if (my $value = $Units{$unit}) {
122 10         15 $amount =~ s/,/./;
123 10         37 $duration += $amount * $value;
124             } else {
125 0         0 return $orig_timespec;
126             }
127             }
128              
129 8 100       23 if ($timespec =~ /\S/) {
130 2         5 return $orig_timespec;
131             }
132              
133 6         19 return sprintf "%.0f", $duration + time;
134             }
135              
136              
137             1;
138              
139             __END__