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.3521';
5 188     188   199301 use strict;
  188         469  
  188         5345  
6 188     188   1048 use warnings;
  188         435  
  188         4271  
7              
8 188     188   991 use Carp;
  188         449  
  188         9704  
9 188     188   81448 use URI::Escape;
  188         285799  
  188         12411  
10              
11 188     188   1427 use base 'Dancer::Object';
  188         513  
  188         236095  
12             __PACKAGE__->attributes( qw/name expires domain path same_site secure http_only/ );
13              
14             sub init {
15 88     88 1 334 my ($self, %args) = @_;
16 88         370 $self->value($args{value});
17 88 100       338 if (my $time = $self->expires) {
18             # First, normalize things like +2h to # of seconds
19 16 100       90 $time = _parse_duration($time) if $time !~ /^\d+$/;
20              
21             # Then translate to a gmt string, if it isn't one already
22 16 100       88 $time = _epoch_to_gmtstring($time) if $time =~ /^\d+$/;
23              
24 16         59 $self->expires($time);
25             }
26 88 100       318 $self->path('/') unless defined $self->path;
27              
28             # If we have a same_site attribute, ensure it's sane:
29 88 100       324 if (my $same_site = $self->same_site) {
30 35 50       412 if ($same_site !~ m{^(Strict|Lax|None)$}i) {
31 0         0 Carp::croak(
32             "Invalid same_site value '$same_site'"
33             . " - must be 'Strict', 'Lax' or 'None', see RFC6265bis"
34             );
35             } else {
36             # Normalise case
37 35         282 $self->same_site(ucfirst lc $same_site);
38             }
39             }
40             }
41              
42             sub to_header {
43 37     37 1 2493 my $self = shift;
44 37         78 my $header = '';
45              
46 37         121 my $value = join('&', map {uri_escape($_)} $self->value);
  40         243  
47 37   100     1085 my $no_httponly = defined( $self->http_only ) && $self->http_only == 0;
48              
49 37         145 my $name = $self->name;
50 37         102 $name =~ s/[=,; \t\r\n\013\014]//mg;
51              
52 37         134 my @headers = $name . '=' . $value;
53 37 50       102 push @headers, "path=" . $self->path if $self->path;
54 37 100       112 push @headers, "expires=" . $self->expires if $self->expires;
55 37 100       169 push @headers, "domain=" . $self->domain if $self->domain;
56 37 100       120 push @headers, "Secure" if $self->secure;
57 37 100       98 push @headers, "SameSite=" . $self->same_site if $self->same_site;
58 37 100       132 push @headers, 'HttpOnly' unless $no_httponly;
59              
60 37         237 return join '; ', @headers;
61             }
62              
63             sub value {
64 484     484 1 905 my ( $self, $value ) = @_;
65 484 100       975 if ( defined $value ) {
66 88 100       477 my @values =
    100          
67             ref $value eq 'ARRAY' ? @$value
68             : ref $value eq 'HASH' ? %$value
69             : ($value);
70 88         375 $self->{'value'} = [@values];
71             }
72 484 100       1434 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  181         892  
73             }
74              
75             sub _epoch_to_gmtstring {
76 14     14   26 my ($epoch) = @_;
77              
78 14         140 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($epoch);
79 14         50 my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
80 14         26 my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
81              
82 14         93 return sprintf "%s, %02d-%s-%d %02d:%02d:%02d GMT",
83             $days[$wday],
84             $mday,
85             $months[$mon],
86             ($year + 1900),
87             $hour, $min, $sec;
88             }
89              
90             # This map is taken from Cache and Cache::Cache
91             # map of expiration formats to their respective time in seconds
92             my %Units = ( map(($_, 1), qw(s second seconds sec secs)),
93             map(($_, 60), qw(m minute minutes min mins)),
94             map(($_, 60*60), qw(h hr hour hours)),
95             map(($_, 60*60*24), qw(d day days)),
96             map(($_, 60*60*24*7), qw(w week weeks)),
97             map(($_, 60*60*24*30), qw(M month months)),
98             map(($_, 60*60*24*365), qw(y year years)) );
99              
100             # This code is taken from Time::Duration::Parse, except if it isn't
101             # understood it just passes it through and it adds the current time.
102             sub _parse_duration {
103 8     8   17 my $timespec = shift;
104 8         12 my $orig_timespec = $timespec;
105              
106             # Treat a plain number as a number of seconds (and parse it later)
107 8 50       39 if ($timespec =~ /^\s*([-+]?\d+(?:[.,]\d+)?)\s*$/) {
108 0         0 $timespec = "$1s";
109             }
110              
111             # Convert hh:mm(:ss)? to something we understand
112 8         17 $timespec =~ s/\b(\d+):(\d\d):(\d\d)\b/$1h $2m $3s/g;
113 8         11 $timespec =~ s/\b(\d+):(\d\d)\b/$1h $2m/g;
114              
115 8         13 my $duration = 0;
116 8         46 while ($timespec =~ s/^\s*([-+]?\d+(?:[.,]\d+)?)\s*([a-zA-Z]+)(?:\s*(?:,|and)\s*)*//i) {
117 10         56 my($amount, $unit) = ($1, $2);
118 10 100       26 $unit = lc($unit) unless length($unit) == 1;
119              
120 10 50       23 if (my $value = $Units{$unit}) {
121 10         14 $amount =~ s/,/./;
122 10         38 $duration += $amount * $value;
123             } else {
124 0         0 return $orig_timespec;
125             }
126             }
127              
128 8 100       21 if ($timespec =~ /\S/) {
129 2         5 return $orig_timespec;
130             }
131              
132 6         17 return sprintf "%.0f", $duration + time;
133             }
134              
135              
136             1;
137              
138             __END__