File Coverage

blib/lib/CGI/Simple/Cookie.pm
Criterion Covered Total %
statement 109 109 100.0
branch 64 74 86.4
condition 13 20 65.0
subroutine 20 20 100.0
pod 9 15 60.0
total 215 238 90.3


line stmt bran cond sub pod time code
1             package CGI::Simple::Cookie;
2              
3             # Original version Copyright 1995-1999, Lincoln D. Stein. All rights reserved.
4             # It may be used and modified freely, but I do request that this copyright
5             # notice remain attached to the file. You may modify this module as you
6             # wish, but if you redistribute a modified version, please attach a note
7             # listing the modifications you have made.
8              
9             # This version Copyright 2001, Dr James Freeman. All rights reserved.
10             # Renamed, strictified, and generally hacked code. Now 30% shorter.
11             # Interface remains identical and passes all original CGI::Cookie tests
12              
13 3     3   9682 use strict;
  3         6  
  3         110  
14 3     3   17 use warnings;
  3         6  
  3         111  
15 3     3   17 use vars '$VERSION';
  3         6  
  3         210  
16             $VERSION = '1.27';
17 3     3   19 use CGI::Simple::Util qw(rearrange unescape escape);
  3         6  
  3         255  
18 3     3   1265 use overload '""' => \&as_string, 'cmp' => \&compare, 'fallback' => 1;
  3         1026  
  3         31  
19              
20             # fetch a list of cookies from the environment and return as a hash.
21             # the cookies are parsed as normal escaped URL data.
22             sub fetch {
23 6     6 0 1232 my $self = shift;
24 6   100     36 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
25 6 100       24 return () unless $raw_cookie;
26 4         18 return $self->parse( $raw_cookie );
27             }
28              
29             sub parse {
30 8     8 0 2293 my ( $self, $raw_cookie ) = @_;
31 8 50       21 return () unless $raw_cookie;
32 8         14 my %results;
33 8         65 my @pairs = split "[;,] ?", $raw_cookie;
34 8         23 for my $pair ( @pairs ) {
35             # trim leading trailing whitespace
36 27         70 $pair =~ s/^\s+//;
37 27         74 $pair =~ s/\s+$//;
38 27         84 my ( $key, $value ) = split( "=", $pair, 2 );
39 27 50       67 next if !defined( $value );
40 27         40 my @values = ();
41 27 50       59 if ( $value ne '' ) {
42 27         145 @values = map unescape( $_ ), split( /[&;]/, $value . '&dmy' );
43 27         51 pop @values;
44             }
45 27         57 $key = unescape( $key );
46              
47             # A bug in Netscape can cause several cookies with same name to
48             # appear. The FIRST one in HTTP_COOKIE is the most recent version.
49 27   33     135 $results{$key} ||= $self->new( -name => $key, -value => \@values );
50             }
51 8 100       70 return wantarray ? %results : \%results;
52             }
53              
54             # fetch a list of cookies from the environment and return as a hash.
55             # the cookie values are not unescaped or altered in any way.
56             sub raw_fetch {
57 6   100 6 0 4382 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
58 6 100       22 return () unless $raw_cookie;
59 4         10 my %results;
60 4         38 my @pairs = split "; ?", $raw_cookie;
61 4         12 for my $pair ( @pairs ) {
62 12         50 $pair =~ s/^\s+|\s+$//; # trim leading trailing whitespace
63 12         38 my ( $key, $value ) = split "=", $pair;
64              
65             # fixed bug that does not allow 0 as a cookie value thanks Jose Mico
66             # $value ||= 0;
67 12 50       29 $value = defined $value ? $value : '';
68 12         29 $results{$key} = $value;
69             }
70 4 100       28 return wantarray ? %results : \%results;
71             }
72              
73             sub new {
74 52     52 0 6226 my ( $class, @params ) = @_;
75 52   33     186 $class = ref( $class ) || $class;
76             my (
77 52         305 $name, $value, $path, $domain,
78             $secure, $expires, $max_age, $httponly, $samesite
79             )
80             = rearrange(
81             [
82             'NAME', [ 'VALUE', 'VALUES' ],
83             'PATH', 'DOMAIN',
84             'SECURE', 'EXPIRES',
85             'MAX-AGE', 'HTTPONLY', 'SAMESITE'
86             ],
87             @params
88             );
89 52 50 33     246 return undef unless defined $name and defined $value;
90 52         99 my $self = {};
91 52         96 bless $self, $class;
92 52         134 $self->name( $name );
93 52         129 $self->value( $value );
94 52   100     192 $path ||= "/";
95 52 50       263 $self->path( $path ) if defined $path;
96 52 100       124 $self->domain( $domain ) if defined $domain;
97 52 100       108 $self->secure( $secure ) if defined $secure;
98 52 100       119 $self->expires( $expires ) if defined $expires;
99 52 100       106 $self->max_age( $max_age ) if defined $max_age;
100 52 100       119 $self->httponly( $httponly ) if defined $httponly;
101 52 100       94 $self->samesite( $samesite ) if defined $samesite;
102 52         223 return $self;
103             }
104              
105             sub as_string {
106 77     77 0 2125 my $self = shift;
107 77 50       143 return "" unless $self->name;
108 77         158 my $name = escape( $self->name );
109 77         164 my $value = join "&", map { escape( $_ ) } $self->value;
  139         258  
110 77         231 my @cookie = ( "$name=$value" );
111 77 100       149 push @cookie, "domain=" . $self->domain if $self->domain;
112 77 50       150 push @cookie, "path=" . $self->path if $self->path;
113 77 100       150 push @cookie, "expires=" . $self->expires if $self->expires;
114 77 100       138 push @cookie, "max-age=" . $self->max_age if $self->max_age;
115 77 100       131 push @cookie, "secure" if $self->secure;
116 77 100       132 push @cookie, "HttpOnly" if $self->httponly;
117 77 100       139 push @cookie, "SameSite=" . $self->samesite if $self->samesite;
118 77         521 return join "; ", @cookie;
119             }
120              
121             sub compare {
122 11     11 0 1395 my ( $self, $value ) = @_;
123 11         25 return "$self" cmp $value;
124             }
125              
126             # accessors subs
127             sub name {
128 213     213 1 1515 my ( $self, $name ) = @_;
129 213 100       516 $self->{'name'} = $name if defined $name;
130 213         514 return $self->{'name'};
131             }
132              
133             sub value {
134 156     156 1 2643 my ( $self, $value ) = @_;
135 156 100       310 if ( defined $value ) {
136             my @values
137 53 50       185 = ref $value eq 'ARRAY' ? @$value
    100          
138             : ref $value eq 'HASH' ? %$value
139             : ( $value );
140 53         137 $self->{'value'} = [@values];
141             }
142 156 100       363 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  82         219  
143             }
144              
145             sub domain {
146 134     134 1 209 my ( $self, $domain ) = @_;
147 134 100       258 $self->{'domain'} = $domain if defined $domain;
148 134         331 return $self->{'domain'};
149             }
150              
151             sub secure {
152 95     95 1 154 my ( $self, $secure ) = @_;
153 95 100       166 $self->{'secure'} = $secure if defined $secure;
154 95         187 return $self->{'secure'};
155             }
156              
157             sub expires {
158 136     136 1 225 my ( $self, $expires ) = @_;
159 136 100       269 $self->{'expires'} = CGI::Simple::Util::expires( $expires, 'cookie' )
160             if defined $expires;
161 136         328 return $self->{'expires'};
162             }
163              
164             sub max_age {
165 98     98 1 172 my ( $self, $max_age ) = @_;
166 98 100       175 $self->{'max-age'}
167             = CGI::Simple::Util::_expire_calc( $max_age ) - time()
168             if defined $max_age;
169 98         216 return $self->{'max-age'};
170             }
171              
172             sub path {
173 213     213 1 340 my ( $self, $path ) = @_;
174 213 100       404 $self->{'path'} = $path if defined $path;
175 213         461 return $self->{'path'};
176             }
177              
178             sub httponly {
179 95     95 1 155 my ( $self, $httponly ) = @_;
180 95 100       169 $self->{'httponly'} = $httponly if defined $httponly;
181 95         195 return $self->{'httponly'};
182             }
183              
184             my %_legal_samesite = ( Strict => 1, Lax => 1, None => 1 );
185             sub samesite {
186 96     96 1 148 my $self = shift;
187 96 100       203 my $samesite = ucfirst lc +shift if @_; # Normalize casing.
188 96 50 66     253 $self->{'samesite'} = $samesite if $samesite and $_legal_samesite{$samesite};
189 96         208 return $self->{'samesite'};
190             }
191              
192             1;
193              
194             __END__