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   9307 use strict;
  3         5  
  3         112  
14 3     3   18 use warnings;
  3         6  
  3         106  
15 3     3   16 use vars '$VERSION';
  3         15  
  3         226  
16             $VERSION = '1.280';
17 3     3   20 use CGI::Simple::Util qw(rearrange unescape escape);
  3         5  
  3         356  
18 3     3   1206 use overload '""' => \&as_string, 'cmp' => \&compare, 'fallback' => 1;
  3         1031  
  3         33  
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 1227 my $self = shift;
24 6   100     37 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
25 6 100       22 return () unless $raw_cookie;
26 4         17 return $self->parse( $raw_cookie );
27             }
28              
29             sub parse {
30 8     8 0 1980 my ( $self, $raw_cookie ) = @_;
31 8 50       21 return () unless $raw_cookie;
32 8         14 my %results;
33 8         53 my @pairs = split "[;,] ?", $raw_cookie;
34 8         19 for my $pair ( @pairs ) {
35             # trim leading trailing whitespace
36 27         67 $pair =~ s/^\s+//;
37 27         63 $pair =~ s/\s+$//;
38 27         82 my ( $key, $value ) = split( "=", $pair, 2 );
39 27 50       58 next if !defined( $value );
40 27         40 my @values = ();
41 27 50       57 if ( $value ne '' ) {
42 27         128 @values = map unescape( $_ ), split( /[&;]/, $value . '&dmy' );
43 27         63 pop @values;
44             }
45 27         53 $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     116 $results{$key} ||= $self->new( -name => $key, -value => \@values );
50             }
51 8 100       62 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 4256 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
58 6 100       20 return () unless $raw_cookie;
59 4         7 my %results;
60 4         33 my @pairs = split "; ?", $raw_cookie;
61 4         11 for my $pair ( @pairs ) {
62 12         46 $pair =~ s/^\s+|\s+$//; # trim leading trailing whitespace
63 12         30 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       31 $value = defined $value ? $value : '';
68 12         30 $results{$key} = $value;
69             }
70 4 100       25 return wantarray ? %results : \%results;
71             }
72              
73             sub new {
74 52     52 0 5999 my ( $class, @params ) = @_;
75 52   33     165 $class = ref( $class ) || $class;
76             my (
77 52         214 $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     232 return undef unless defined $name and defined $value;
90 52         75 my $self = {};
91 52         87 bless $self, $class;
92 52         119 $self->name( $name );
93 52         110 $self->value( $value );
94 52   100     181 $path ||= "/";
95 52 50       146 $self->path( $path ) if defined $path;
96 52 100       108 $self->domain( $domain ) if defined $domain;
97 52 100       99 $self->secure( $secure ) if defined $secure;
98 52 100       103 $self->expires( $expires ) if defined $expires;
99 52 100       97 $self->max_age( $max_age ) if defined $max_age;
100 52 100       110 $self->httponly( $httponly ) if defined $httponly;
101 52 100       99 $self->samesite( $samesite ) if defined $samesite;
102 52         193 return $self;
103             }
104              
105             sub as_string {
106 77     77 0 2453 my $self = shift;
107 77 50       140 return "" unless $self->name;
108 77         128 my $name = escape( $self->name );
109 77         176 my $value = join "&", map { escape( $_ ) } $self->value;
  139         244  
110 77         211 my @cookie = ( "$name=$value" );
111 77 100       148 push @cookie, "domain=" . $self->domain if $self->domain;
112 77 50       146 push @cookie, "path=" . $self->path if $self->path;
113 77 100       137 push @cookie, "expires=" . $self->expires if $self->expires;
114 77 100       144 push @cookie, "max-age=" . $self->max_age if $self->max_age;
115 77 100       128 push @cookie, "secure" if $self->secure;
116 77 100       125 push @cookie, "HttpOnly" if $self->httponly;
117 77 100       139 push @cookie, "SameSite=" . $self->samesite if $self->samesite;
118 77         530 return join "; ", @cookie;
119             }
120              
121             sub compare {
122 11     11 0 1284 my ( $self, $value ) = @_;
123 11         25 return "$self" cmp $value;
124             }
125              
126             # accessors subs
127             sub name {
128 213     213 1 1494 my ( $self, $name ) = @_;
129 213 100       496 $self->{'name'} = $name if defined $name;
130 213         503 return $self->{'name'};
131             }
132              
133             sub value {
134 156     156 1 2358 my ( $self, $value ) = @_;
135 156 100       307 if ( defined $value ) {
136             my @values
137 53 50       178 = ref $value eq 'ARRAY' ? @$value
    100          
138             : ref $value eq 'HASH' ? %$value
139             : ( $value );
140 53         131 $self->{'value'} = [@values];
141             }
142 156 100       361 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  82         253  
143             }
144              
145             sub domain {
146 134     134 1 204 my ( $self, $domain ) = @_;
147 134 100       245 $self->{'domain'} = $domain if defined $domain;
148 134         376 return $self->{'domain'};
149             }
150              
151             sub secure {
152 95     95 1 143 my ( $self, $secure ) = @_;
153 95 100       159 $self->{'secure'} = $secure if defined $secure;
154 95         176 return $self->{'secure'};
155             }
156              
157             sub expires {
158 136     136 1 232 my ( $self, $expires ) = @_;
159 136 100       246 $self->{'expires'} = CGI::Simple::Util::expires( $expires, 'cookie' )
160             if defined $expires;
161 136         324 return $self->{'expires'};
162             }
163              
164             sub max_age {
165 98     98 1 163 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         221 return $self->{'max-age'};
170             }
171              
172             sub path {
173 213     213 1 329 my ( $self, $path ) = @_;
174 213 100       378 $self->{'path'} = $path if defined $path;
175 213         441 return $self->{'path'};
176             }
177              
178             sub httponly {
179 95     95 1 149 my ( $self, $httponly ) = @_;
180 95 100       172 $self->{'httponly'} = $httponly if defined $httponly;
181 95         176 return $self->{'httponly'};
182             }
183              
184             my %_legal_samesite = ( Strict => 1, Lax => 1, None => 1 );
185             sub samesite {
186 96     96 1 138 my $self = shift;
187 96 100       217 my $samesite = ucfirst lc +shift if @_; # Normalize casing.
188 96 50 66     191 $self->{'samesite'} = $samesite if $samesite and $_legal_samesite{$samesite};
189 96         189 return $self->{'samesite'};
190             }
191              
192             1;
193              
194             __END__