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   9275 use strict;
  3         5  
  3         119  
14 3     3   16 use warnings;
  3         7  
  3         113  
15 3     3   18 use vars '$VERSION';
  3         5  
  3         211  
16             $VERSION = '1.26';
17 3     3   21 use CGI::Simple::Util qw(rearrange unescape escape);
  3         5  
  3         289  
18 3     3   1201 use overload '""' => \&as_string, 'cmp' => \&compare, 'fallback' => 1;
  3         1024  
  3         38  
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 1271 my $self = shift;
24 6   100     36 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
25 6 100       23 return () unless $raw_cookie;
26 4         19 return $self->parse( $raw_cookie );
27             }
28              
29             sub parse {
30 8     8 0 1961 my ( $self, $raw_cookie ) = @_;
31 8 50       21 return () unless $raw_cookie;
32 8         12 my %results;
33 8         56 my @pairs = split "[;,] ?", $raw_cookie;
34 8         18 for my $pair ( @pairs ) {
35             # trim leading trailing whitespace
36 27         76 $pair =~ s/^\s+//;
37 27         61 $pair =~ s/\s+$//;
38 27         81 my ( $key, $value ) = split( "=", $pair, 2 );
39 27 50       62 next if !defined( $value );
40 27         37 my @values = ();
41 27 50       60 if ( $value ne '' ) {
42 27         138 @values = map unescape( $_ ), split( /[&;]/, $value . '&dmy' );
43 27         50 pop @values;
44             }
45 27         56 $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     123 $results{$key} ||= $self->new( -name => $key, -value => \@values );
50             }
51 8 100       61 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 4262 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
58 6 100       21 return () unless $raw_cookie;
59 4         9 my %results;
60 4         31 my @pairs = split "; ?", $raw_cookie;
61 4         13 for my $pair ( @pairs ) {
62 12         47 $pair =~ s/^\s+|\s+$//; # trim leading trailing whitespace
63 12         33 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       30 $value = defined $value ? $value : '';
68 12         29 $results{$key} = $value;
69             }
70 4 100       26 return wantarray ? %results : \%results;
71             }
72              
73             sub new {
74 52     52 0 6012 my ( $class, @params ) = @_;
75 52   33     170 $class = ref( $class ) || $class;
76             my (
77 52         217 $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     237 return undef unless defined $name and defined $value;
90 52         93 my $self = {};
91 52         85 bless $self, $class;
92 52         132 $self->name( $name );
93 52         116 $self->value( $value );
94 52   100     182 $path ||= "/";
95 52 50       156 $self->path( $path ) if defined $path;
96 52 100       105 $self->domain( $domain ) if defined $domain;
97 52 100       101 $self->secure( $secure ) if defined $secure;
98 52 100       108 $self->expires( $expires ) if defined $expires;
99 52 100       101 $self->max_age( $max_age ) if defined $max_age;
100 52 100       115 $self->httponly( $httponly ) if defined $httponly;
101 52 100       95 $self->samesite( $samesite ) if defined $samesite;
102 52         199 return $self;
103             }
104              
105             sub as_string {
106 77     77 0 2150 my $self = shift;
107 77 50       135 return "" unless $self->name;
108 77         137 my $name = escape( $self->name );
109 77         160 my $value = join "&", map { escape( $_ ) } $self->value;
  139         257  
110 77         262 my @cookie = ( "$name=$value" );
111 77 100       181 push @cookie, "domain=" . $self->domain if $self->domain;
112 77 50       145 push @cookie, "path=" . $self->path if $self->path;
113 77 100       148 push @cookie, "expires=" . $self->expires if $self->expires;
114 77 100       142 push @cookie, "max-age=" . $self->max_age if $self->max_age;
115 77 100       132 push @cookie, "secure" if $self->secure;
116 77 100       133 push @cookie, "HttpOnly" if $self->httponly;
117 77 100       131 push @cookie, "SameSite=" . $self->samesite if $self->samesite;
118 77         525 return join "; ", @cookie;
119             }
120              
121             sub compare {
122 11     11 0 1390 my ( $self, $value ) = @_;
123 11         23 return "$self" cmp $value;
124             }
125              
126             # accessors subs
127             sub name {
128 213     213 1 1455 my ( $self, $name ) = @_;
129 213 100       490 $self->{'name'} = $name if defined $name;
130 213         528 return $self->{'name'};
131             }
132              
133             sub value {
134 156     156 1 2362 my ( $self, $value ) = @_;
135 156 100       329 if ( defined $value ) {
136             my @values
137 53 50       161 = ref $value eq 'ARRAY' ? @$value
    100          
138             : ref $value eq 'HASH' ? %$value
139             : ( $value );
140 53         143 $self->{'value'} = [@values];
141             }
142 156 100       354 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  82         233  
143             }
144              
145             sub domain {
146 134     134 1 217 my ( $self, $domain ) = @_;
147 134 100       231 $self->{'domain'} = $domain if defined $domain;
148 134         321 return $self->{'domain'};
149             }
150              
151             sub secure {
152 95     95 1 147 my ( $self, $secure ) = @_;
153 95 100       168 $self->{'secure'} = $secure if defined $secure;
154 95         184 return $self->{'secure'};
155             }
156              
157             sub expires {
158 136     136 1 227 my ( $self, $expires ) = @_;
159 136 100       247 $self->{'expires'} = CGI::Simple::Util::expires( $expires, 'cookie' )
160             if defined $expires;
161 136         399 return $self->{'expires'};
162             }
163              
164             sub max_age {
165 98     98 1 153 my ( $self, $max_age ) = @_;
166 98 100       198 $self->{'max-age'}
167             = CGI::Simple::Util::_expire_calc( $max_age ) - time()
168             if defined $max_age;
169 98         228 return $self->{'max-age'};
170             }
171              
172             sub path {
173 213     213 1 322 my ( $self, $path ) = @_;
174 213 100       393 $self->{'path'} = $path if defined $path;
175 213         439 return $self->{'path'};
176             }
177              
178             sub httponly {
179 95     95 1 138 my ( $self, $httponly ) = @_;
180 95 100       176 $self->{'httponly'} = $httponly if defined $httponly;
181 95         172 return $self->{'httponly'};
182             }
183              
184             my %_legal_samesite = ( Strict => 1, Lax => 1, None => 1 );
185             sub samesite {
186 96     96 1 149 my $self = shift;
187 96 100       184 my $samesite = ucfirst lc +shift if @_; # Normalize casing.
188 96 50 66     186 $self->{'samesite'} = $samesite if $samesite and $_legal_samesite{$samesite};
189 96         199 return $self->{'samesite'};
190             }
191              
192             1;
193              
194             __END__