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   110189 use 5.008001;
  3         24  
4 3     3   13 use strict;
  3         5  
  3         47  
5 3     3   12 use warnings;
  3         3  
  3         74  
6 3     3   13 use base qw/Exporter/;
  3         4  
  3         206  
7 3     3   1068 use URI::Escape;
  3         3644  
  3         511  
8              
9             BEGIN {
10 3     3   10 our $VERSION = "0.11";
11 3         8 our @EXPORT = qw/bake_cookie crush_cookie/;
12 3         5 my $use_pp = $ENV{COOKIE_BAKER_PP};
13 3 50       10 if (!$use_pp) {
14 3         6 eval {
15 3         348 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         13 $use_pp = !!$@;
22             }
23 3 50       8 if ($use_pp) {
24 3         1154 *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 26     26 1 10696 my ($name,$val) = @_;
33              
34 26 50       56 return '' unless defined $val;
35 26 100       50 my %args = ref $val ? %{$val} : (value => $val);
  25         82  
36 26 50       81 $name = URI::Escape::uri_escape($name) if $name =~ m![^a-zA-Z\-\._~]!;
37 26         77 my $cookie = "$name=" . URI::Escape::uri_escape($args{value}) . '; ';
38 26 50       300 $cookie .= 'domain=' . $args{domain} . '; ' if $args{domain};
39 26 100       67 $cookie .= 'path='. $args{path} . '; ' if $args{path};
40 26 100 100     81 $cookie .= 'expires=' . _date($args{expires}) . '; ' if exists $args{expires} && defined $args{expires};
41 26 100       47 $cookie .= 'max-age=' . $args{"max-age"} . '; ' if exists $args{"max-age"};
42 26 100 100     56 if (exists $args{samesite} && $args{samesite} =~ m/^(?:lax|strict|none)/i) {
43 3         9 $cookie .= 'SameSite=' . ucfirst(lc($args{samesite})) . '; '
44             }
45 26 100       38 $cookie .= 'secure; ' if $args{secure};
46 26 100       36 $cookie .= 'HttpOnly; ' if $args{httponly};
47 26         42 substr($cookie,-2,2,'');
48 26         75 $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   18 my $expires = shift;
65              
66 13         24 my $expires_at;
67 13 100       70 if ($expires =~ /^\d+$/) {
    100          
    100          
68             # all numbers -> epoch date
69 2         3 $expires_at = $expires;
70             }
71             elsif ( $expires =~ /^([-+]?(?:\d+|\d*\.\d*))([smhdMy]?)/ ) {
72 3     3   21 no warnings;
  3         4  
  3         963  
73 9   100     41 my $offset = ($term{$2} || 1) * $1;
74 9         20 $expires_at = time + $offset;
75             }
76             elsif ( $expires eq 'now' ) {
77 1         3 $expires_at = time;
78             }
79             else {
80 1         3 return $expires;
81             }
82 12         104 my($sec, $min, $hour, $mday, $mon, $year, $wday) = gmtime($expires_at);
83 12         22 $year += 1900;
84             # (cookies use '-' as date separator, HTTP uses ' ')
85 12         69 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 8865 my $cookie_string = shift;
91 44 100       87 return {} unless $cookie_string;
92 40         48 my %results;
93 40         303 my @pairs = grep m/=/, split /; ?/, $cookie_string;
94 40         75 for my $pair ( @pairs ) {
95             # trim leading trailing whitespace
96 114         217 $pair =~ s/^\s+//; $pair =~ s/\s+$//;
  114         225  
97              
98 114         259 my ($key, $value) = split( "=", $pair, 2 );
99              
100 114         204 $key = URI::Escape::uri_unescape($key);
101              
102             # Values can be quoted
103 114 50       692 $value = "" unless defined $value;
104 114         144 $value =~ s/\A"(.*)"\z/$1/;
105 114         157 $value = URI::Escape::uri_unescape($value);
106              
107             # Take the first one like CGI.pm or rack do
108 114 100       885 $results{$key} = $value unless exists $results{$key};
109             }
110 40         112 return \%results;
111             }
112              
113             1;
114             __END__