File Coverage

blib/lib/CGI/Simple/Cookie.pm
Criterion Covered Total %
statement 121 121 100.0
branch 77 88 87.5
condition 15 23 65.2
subroutine 22 22 100.0
pod 11 17 64.7
total 246 271 90.7


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   14779 use strict;
  3         16  
  3         188  
14 3     3   18 use warnings;
  3         7  
  3         260  
15 3     3   22 use vars '$VERSION';
  3         7  
  3         235  
16             $VERSION = '1.282';
17 3     3   18 use CGI::Simple::Util qw(rearrange unescape escape);
  3         7  
  3         506  
18 3     3   22 use overload '""' => \&as_string, 'cmp' => \&compare, 'fallback' => 1;
  3         6  
  3         35  
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 1655 my $self = shift;
24 6   100     57 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
25 6 100       29 return () unless $raw_cookie;
26 4         16 return $self->parse( $raw_cookie );
27             }
28              
29             sub parse {
30 8     8 0 257270 my ( $self, $raw_cookie ) = @_;
31 8 50       27 return () unless $raw_cookie;
32 8         15 my %results;
33 8         73 my @pairs = split "[;,] ?", $raw_cookie;
34 8         24 for my $pair ( @pairs ) {
35             # trim leading trailing whitespace
36 27         108 $pair =~ s/^\s+//;
37 27         80 $pair =~ s/\s+$//;
38 27         103 my ( $key, $value ) = split( "=", $pair, 2 );
39 27 50       78 next if !defined( $value );
40 27         73 my @values = ();
41 27 50       78 if ( $value ne '' ) {
42 27         187 @values = map unescape( $_ ), split( /[&;]/, $value . '&dmy' );
43 27         69 pop @values;
44             }
45 27         60 $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     205 $results{$key} ||= $self->new( -name => $key, -value => \@values );
50             }
51 8 100       83 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 7190 my $raw_cookie = $ENV{HTTP_COOKIE} || $ENV{COOKIE};
58 6 100       27 return () unless $raw_cookie;
59 4         10 my %results;
60 4         39 my @pairs = split "; ?", $raw_cookie;
61 4         45 for my $pair ( @pairs ) {
62 12         78 $pair =~ s/^\s+|\s+$//; # trim leading trailing whitespace
63 12         39 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       34 $value = defined $value ? $value : '';
68 12         80 $results{$key} = $value;
69             }
70 4 100       42 return wantarray ? %results : \%results;
71             }
72              
73             sub new {
74 52     52 0 8509 my ( $class, @params ) = @_;
75 52   33     208 $class = ref( $class ) || $class;
76             my (
77 52         328 $name, $value, $path, $domain,
78             $secure, $expires, $max_age, $httponly, $samesite,
79             $priority, $partitioned
80             )
81             = rearrange(
82             [
83             'NAME', [ 'VALUE', 'VALUES' ],
84             'PATH', 'DOMAIN',
85             'SECURE', 'EXPIRES',
86             'MAX-AGE', 'HTTPONLY', 'SAMESITE',
87             'PRIORITY', 'PARTITIONED',
88             ],
89             @params
90             );
91 52 50 33     449 return undef unless defined $name and defined $value;
92 52         94 my $self = {};
93 52         122 bless $self, $class;
94 52         189 $self->name( $name );
95 52         146 $self->value( $value );
96 52   100     213 $path ||= "/";
97 52 50       185 $self->path( $path ) if defined $path;
98 52 100       127 $self->domain( $domain ) if defined $domain;
99 52 100       131 $self->secure( $secure ) if defined $secure;
100 52 100       148 $self->expires( $expires ) if defined $expires;
101 52 100       105 $self->max_age( $max_age ) if defined $max_age;
102 52 100       134 $self->httponly( $httponly ) if defined $httponly;
103 52 100       107 $self->samesite( $samesite ) if defined $samesite;
104 52 100       104 $self->priority( $priority ) if defined $priority;
105 52 100       110 $self->partitioned( $partitioned ) if defined $partitioned;
106 52         295 return $self;
107             }
108              
109             sub as_string {
110 81     81 0 2822 my $self = shift;
111 81 50       197 return "" unless $self->name;
112 81         171 my $name = escape( $self->name );
113 81         204 my $value = join "&", map { escape( $_ ) } $self->value;
  143         304  
114 81         291 my @cookie = ( "$name=$value" );
115 81 100       3901 push @cookie, "domain=" . $self->domain if $self->domain;
116 81 50       189 push @cookie, "path=" . $self->path if $self->path;
117 81 100       185 push @cookie, "expires=" . $self->expires if $self->expires;
118 81 100       184 push @cookie, "max-age=" . $self->max_age if $self->max_age;
119 81 100       159 push @cookie, "secure" if $self->secure;
120 81 100       182 push @cookie, "HttpOnly" if $self->httponly;
121 81 100       219 push @cookie, "SameSite=" . $self->samesite if $self->samesite;
122 81 100       184 push @cookie,"Priority=".$self->priority if $self->priority;
123 81 100       174 push @cookie,"Partitioned" if $self->partitioned;
124 81         635 return join "; ", @cookie;
125             }
126              
127             sub compare {
128 11     11 0 3085 my ( $self, $value ) = @_;
129 11         30 return "$self" cmp $value;
130             }
131              
132             # accessors subs
133             sub name {
134 221     221 1 2475 my ( $self, $name ) = @_;
135 221 100       625 $self->{'name'} = $name if defined $name;
136 221         737 return $self->{'name'};
137             }
138              
139             sub value {
140 160     160 1 3712 my ( $self, $value ) = @_;
141 160 100       384 if ( defined $value ) {
142             my @values
143 53 50       319 = ref $value eq 'ARRAY' ? @$value
    100          
144             : ref $value eq 'HASH' ? %$value
145             : ( $value );
146 53         226 $self->{'value'} = [@values];
147             }
148 160 100       470 return wantarray ? @{ $self->{'value'} } : $self->{'value'}->[0];
  86         295  
149             }
150              
151             sub domain {
152 140     140 1 261 my ( $self, $domain ) = @_;
153 140 100       324 $self->{'domain'} = $domain if defined $domain;
154 140         764 return $self->{'domain'};
155             }
156              
157             sub secure {
158 99     99 1 204 my ( $self, $secure ) = @_;
159 99 100       232 $self->{'secure'} = $secure if defined $secure;
160 99         329 return $self->{'secure'};
161             }
162              
163             sub expires {
164 142     142 1 301 my ( $self, $expires ) = @_;
165 142 100       328 $self->{'expires'} = CGI::Simple::Util::expires( $expires, 'cookie' )
166             if defined $expires;
167 142         405 return $self->{'expires'};
168             }
169              
170             sub max_age {
171 104     104 1 180 my ( $self, $max_age ) = @_;
172 104 100       234 $self->{'max-age'}
173             = CGI::Simple::Util::_expire_calc( $max_age ) - time()
174             if defined $max_age;
175 104         266 return $self->{'max-age'};
176             }
177              
178             sub path {
179 221     221 1 404 my ( $self, $path ) = @_;
180 221 100       447 $self->{'path'} = $path if defined $path;
181 221         578 return $self->{'path'};
182             }
183              
184             sub httponly {
185 99     99 1 190 my ( $self, $httponly ) = @_;
186 99 100       227 $self->{'httponly'} = $httponly if defined $httponly;
187 99         226 return $self->{'httponly'};
188             }
189              
190             sub partitioned { # Partitioned
191 85     85 1 152 my ( $self, $partitioned ) = @_;
192 85 100       173 $self->{'partitioned'} = $partitioned if defined $partitioned;
193 85         218 return $self->{'partitioned'};
194             }
195              
196             my %_legal_samesite = ( Strict => 1, Lax => 1, None => 1 );
197             sub samesite {
198 102     102 1 181 my $self = shift;
199 102 100       236 my $samesite = ucfirst lc +shift if @_; # Normalize casing.
200 102 50 66     256 $self->{'samesite'} = $samesite if $samesite and $_legal_samesite{$samesite};
201 102         282 return $self->{'samesite'};
202             }
203              
204             my %_legal_priority = ( Low => 1, Medium => 1, High => 1 );
205             sub priority {
206 95     95 1 139 my $self = shift;
207 95 100       188 my $priority = ucfirst lc +shift if @_;
208 95 50 66     250 if ($priority && $_legal_priority{$priority}) {
209 2         8 $self->{'priority'} = $priority;
210             }
211 95         233 return $self->{'priority'};
212             }
213              
214             1;
215              
216             __END__