File Coverage

blib/lib/Cookie/Baker.pm
Criterion Covered Total %
statement 67 71 94.3
branch 30 38 78.9
condition 8 8 100.0
subroutine 10 10 100.0
pod 1 2 50.0
total 116 129 89.9


line stmt bran cond sub pod time code
1             package Cookie::Baker;
2              
3 3     3   132743 use 5.008001;
  3         33  
4 3     3   17 use strict;
  3         5  
  3         58  
5 3     3   15 use warnings;
  3         5  
  3         82  
6 3     3   17 use base qw/Exporter/;
  3         5  
  3         261  
7 3     3   1297 use URI::Escape;
  3         4513  
  3         554  
8              
9             BEGIN {
10 3     3   14 our $VERSION = "0.10";
11 3         7 our @EXPORT = qw/bake_cookie crush_cookie/;
12 3         9 my $use_pp = $ENV{COOKIE_BAKER_PP};
13 3 50       11 if (!$use_pp) {
14 3         4 eval {
15 3         449 require Cookie::Baker::XS;
16 0 0       0 if ( $Cookie::Baker::XS::VERSION < $VERSION ) {
17 0         0 warn "Cookie::Baker::XS $VERSION is require. fallback to PP version";
18 0         0 die;
19             }
20             };
21 3         15 $use_pp = !!$@;
22             }
23 3 50       10 if ($use_pp) {
24 3         1402 *crush_cookie = \&pp_crush_cookie;
25             }
26             else {
27 0         0 *crush_cookie = \&Cookie::Baker::XS::crush_cookie;
28             }
29             }
30              
31             sub bake_cookie {
32 25     25 1 12393 my ($name,$val) = @_;
33              
34 25 50       63 return '' unless defined $val;
35 25 100       66 my %args = ref $val ? %{$val} : (value => $val);
  24         99  
36 25 50       97 $name = URI::Escape::uri_escape($name) if $name =~ m![^a-zA-Z\-\._~]!;
37 25         81 my $cookie = "$name=" . URI::Escape::uri_escape($args{value}) . '; ';
38 25 50       373 $cookie .= 'domain=' . $args{domain} . '; ' if $args{domain};
39 25 100       62 $cookie .= 'path='. $args{path} . '; ' if $args{path};
40 25 100 100     105 $cookie .= 'expires=' . _date($args{expires}) . '; ' if exists $args{expires} && defined $args{expires};
41 25 100       55 $cookie .= 'max-age=' . $args{"max-age"} . '; ' if exists $args{"max-age"};
42 25 100 100     70 if (exists $args{samesite} && $args{samesite} =~ m/^(?:lax|strict)/i) {
43 2         7 $cookie .= 'SameSite=' . ucfirst(lc($args{samesite})) . '; '
44             }
45 25 100       44 $cookie .= 'secure; ' if $args{secure};
46 25 100       39 $cookie .= 'HttpOnly; ' if $args{httponly};
47 25         49 substr($cookie,-2,2,'');
48 25         86 $cookie;
49             }
50              
51             my @MON = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
52             my @WDAY = qw( Sun Mon Tue Wed Thu Fri Sat );
53              
54             my %term = (
55             's' => 1,
56             'm' => 60,
57             'h' => 3600,
58             'd' => 86400,
59             'M' => 86400 * 30,
60             'y' => 86400 * 365,
61             );
62              
63             sub _date {
64 13     13   22 my $expires = shift;
65              
66 13         17 my $expires_at;
67 13 100       86 if ($expires =~ /^\d+$/) {
    100          
    100          
68             # all numbers -> epoch date
69 2         4 $expires_at = $expires;
70             }
71             elsif ( $expires =~ /^([-+]?(?:\d+|\d*\.\d*))([smhdMy]?)/ ) {
72 3     3   25 no warnings;
  3         6  
  3         1181  
73 9   100     47 my $offset = ($term{$2} || 1) * $1;
74 9         25 $expires_at = time + $offset;
75             }
76             elsif ( $expires eq 'now' ) {
77 1         4 $expires_at = time;
78             }
79             else {
80 1         3 return $expires;
81             }
82 12         108 my($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($expires_at);
83 12         27 $year += 1900;
84             # (cookies use '-' as date separator, HTTP uses ' ')
85 12         82 return sprintf("%s, %02d-%s-%04d %02d:%02d:%02d GMT",
86             $WDAY[$wday], $mday, $MON[$mon], $year, $hour, $min, $sec);
87             }
88              
89             sub pp_crush_cookie {
90 44     44 0 11138 my $cookie_string = shift;
91 44 100       107 return {} unless $cookie_string;
92 40         54 my %results;
93 40         384 my @pairs = grep m/=/, split /; ?/, $cookie_string;
94 40         95 for my $pair ( @pairs ) {
95             # trim leading trailing whitespace
96 114         249 $pair =~ s/^\s+//; $pair =~ s/\s+$//;
  114         253  
97              
98 114         298 my ($key, $value) = split( "=", $pair, 2 );
99              
100 114         265 $key = URI::Escape::uri_unescape($key);
101              
102             # Values can be quoted
103 114 50       885 $value = "" unless defined $value;
104 114         188 $value =~ s/\A"(.*)"\z/$1/;
105 114         191 $value = URI::Escape::uri_unescape($value);
106              
107             # Take the first one like CGI.pm or rack do
108 114 100       1125 $results{$key} = $value unless exists $results{$key};
109             }
110 40         149 return \%results;
111             }
112              
113             1;
114             __END__