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.3520';
5 188     188   202507 use strict;
  188         475  
  188         5529  
6 188     188   1069 use warnings;
  188         438  
  188         4482  
7              
8 188     188   949 use Carp;
  188         494  
  188         9927  
9 188     188   83704 use URI::Escape;
  188         293403  
  188         12608  
10              
11 188     188   1463 use base 'Dancer::Object';
  188         495  
  188         247160  
12             __PACKAGE__->attributes( qw/name expires domain path same_site secure http_only/ );
13              
14             sub init {
15 88     88 1 327 my ($self, %args) = @_;
16 88         346 $self->value($args{value});
17 88 100       327 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       84 $time = _epoch_to_gmtstring($time) if $time =~ /^\d+$/;
23              
24 16         43 $self->expires($time);
25             }
26 88 100       336 $self->path('/') unless defined $self->path;
27              
28             # If we have a same_site attribute, ensure it's sane:
29 88 100       305 if (my $same_site = $self->same_site) {
30 35 50       395 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         260 $self->same_site(ucfirst lc $same_site);
38             }
39             }
40             }
41              
42             sub to_header {
43 37     37 1 2775 my $self = shift;
44 37         78 my $header = '';
45              
46 37         112 my $value = join('&', map {uri_escape($_)} $self->value);
  40         204  
47 37   100     1069 my $no_httponly = defined( $self->http_only ) && $self->http_only == 0;
48              
49 37         121 my $name = $self->name;
50 37         96 $name =~ s/[=,; \t\r\n\013\014]//mg;
51              
52 37         127 my @headers = $name . '=' . $value;
53 37 50       107 push @headers, "path=" . $self->path if $self->path;
54 37 100       115 push @headers, "expires=" . $self->expires if $self->expires;
55 37 100       154 push @headers, "domain=" . $self->domain if $self->domain;
56 37 100       118 push @headers, "Secure" if $self->secure;
57 37 100       103 push @headers, "SameSite=" . $self->same_site if $self->same_site;
58 37 100       135 push @headers, 'HttpOnly' unless $no_httponly;
59              
60 37         218 return join '; ', @headers;
61             }
62              
63             sub value {
64 484     484 1 908 my ( $self, $value ) = @_;
65 484 100       956 if ( defined $value ) {
66 88 100       490 my @values =
    100          
67             ref $value eq 'ARRAY' ? @$value
68             : ref $value eq 'HASH' ? %$value
69             : ($value);
70 88         426 $self->{'value'} = [@values];
71             }
72 484 100       1565 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  181         789  
73             }
74              
75             sub _epoch_to_gmtstring {
76 14     14   27 my ($epoch) = @_;
77              
78 14         82 my ($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($epoch);
79 14         48 my @months = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec);
80 14         29 my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
81              
82 14         94 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   15 my $timespec = shift;
104 8         14 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         14 $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         61 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         16 $amount =~ s/,/./;
122 10         39 $duration += $amount * $value;
123             } else {
124 0         0 return $orig_timespec;
125             }
126             }
127              
128 8 100       20 if ($timespec =~ /\S/) {
129 2         6 return $orig_timespec;
130             }
131              
132 6         18 return sprintf "%.0f", $duration + time;
133             }
134              
135              
136             1;
137              
138             __END__