File Coverage

blib/lib/Dancer2/Core/Cookie.pm
Criterion Covered Total %
statement 45 46 97.8
branch 18 24 75.0
condition 2 3 66.6
subroutine 11 11 100.0
pod 0 2 0.0
total 76 86 88.3


line stmt bran cond sub pod time code
1             package Dancer2::Core::Cookie;
2             # ABSTRACT: A cookie representing class
3             $Dancer2::Core::Cookie::VERSION = '0.400001';
4 147     147   71416 use Moo;
  147         6651  
  147         2367  
5 147     147   69547 use URI::Escape;
  147         45769  
  147         9170  
6 147     147   48904 use Dancer2::Core::Types;
  147         511  
  147         1342  
7 147     147   1875899 use Dancer2::Core::Time;
  147         496  
  147         5154  
8 147     147   1144 use Carp 'croak';
  147         328  
  147         8098  
9 147     147   1548 use Ref::Util qw< is_arrayref is_hashref >;
  147         880  
  147         8816  
10 147     147   1038 use overload '""' => \&_get_value;
  147         411  
  147         1563  
11              
12             BEGIN {
13             my $try_xs =
14             exists($ENV{PERL_HTTP_XSCOOKIES}) ? !!$ENV{PERL_HTTP_XSCOOKIES} :
15             exists($ENV{PERL_ONLY}) ? !$ENV{PERL_ONLY} :
16 147 50   147   32207 1;
    50          
17              
18 147         504 my $use_xs = 0;
19 147 50       738 $try_xs and eval {
20 147         65452 require HTTP::XSCookies;
21 147         70820 $use_xs++;
22             };
23 147 50       613 if ( $use_xs ) {
24 147         626 *to_header = \&xs_to_header;
25             }
26             else {
27 0         0 *to_header = \&pp_to_header;
28             }
29 147 50       93474 *_USE_XS = $use_xs ? sub () { !!1 } : sub () { !!0 };
30             }
31              
32             sub xs_to_header {
33 96     96 0 2858 my $self = shift;
34              
35             # HTTP::XSCookies can't handle multi-value cookies.
36 96 100       159 return $self->pp_to_header(@_) if @{[ $self->value ]} > 1;
  96         1963  
37              
38 95         1648 return HTTP::XSCookies::bake_cookie(
39             $self->name,
40             { value => $self->value,
41             path => $self->path,
42             domain => $self->domain,
43             expires => $self->expires,
44             httponly => $self->http_only,
45             secure => $self->secure,
46             samesite => $self->same_site,
47             }
48             );
49             }
50              
51             sub pp_to_header {
52 9     9 0 216 my $self = shift;
53              
54 9         175 my $value = join( '&', map uri_escape($_), $self->value );
55 9   66     299 my $no_httponly = defined( $self->http_only ) && $self->http_only == 0;
56              
57 9         354 my @headers = $self->name . '=' . $value;
58 9 50       184 push @headers, "Path=" . $self->path if $self->path;
59 9 100       340 push @headers, "Expires=" . $self->expires if $self->expires;
60 9 100       235 push @headers, "Domain=" . $self->domain if $self->domain;
61 9 100       203 push @headers, "SameSite=" . $self->same_site if $self->same_site;
62 9 100       210 push @headers, "Secure" if $self->secure;
63 9 100       68 push @headers, 'HttpOnly' unless $no_httponly;
64              
65 9         50 return join '; ', @headers;
66             }
67              
68             has value => (
69             is => 'rw',
70             isa => ArrayRef,
71             required => 0,
72             coerce => sub {
73             my $value = shift;
74             my @values =
75             is_arrayref($value) ? @$value
76             : is_hashref($value) ? %$value
77             : ($value);
78             return [@values];
79             },
80             );
81              
82             around value => sub {
83             my $orig = shift;
84             my $self = shift;
85             my $array = $orig->( $self, @_ );
86             return wantarray ? @$array : $array->[0];
87             };
88              
89             # this is only for overloading; need a real sub to refer to, as the Moose
90             # attribute accessor won't be available at that point.
91 88     88   1764 sub _get_value { shift->value }
92              
93             has name => (
94             is => 'rw',
95             isa => Str,
96             required => 1,
97             );
98              
99             has expires => (
100             is => 'rw',
101             isa => Str,
102             required => 0,
103             coerce => sub {
104             Dancer2::Core::Time->new( expression => $_[0] )->gmt_string;
105             },
106             );
107              
108             has domain => (
109             is => 'rw',
110             isa => Str,
111             required => 0,
112             );
113              
114             has path => (
115             is => 'rw',
116             isa => Str,
117             default => sub {'/'},
118             predicate => 1,
119             );
120              
121             has secure => (
122             is => 'rw',
123             isa => Bool,
124             required => 0,
125             default => sub {0},
126             );
127              
128             has http_only => (
129             is => 'rw',
130             isa => Bool,
131             required => 0,
132             default => sub {1},
133             );
134              
135             has same_site => (
136             is => 'rw',
137             isa => Enum[qw[Strict Lax None]],
138             required => 0,
139             );
140              
141             1;
142              
143             __END__
144              
145             =pod
146              
147             =encoding UTF-8
148              
149             =head1 NAME
150              
151             Dancer2::Core::Cookie - A cookie representing class
152              
153             =head1 VERSION
154              
155             version 0.400001
156              
157             =head1 SYNOPSIS
158              
159             use Dancer2::Core::Cookie;
160              
161             my $cookie = Dancer2::Core::Cookie->new(
162             name => $cookie_name, value => $cookie_value
163             );
164              
165             my $value = $cookie->value;
166              
167             print "$cookie"; # objects stringify to their value.
168              
169             =head1 DESCRIPTION
170              
171             Dancer2::Core::Cookie provides a HTTP cookie object to work with cookies.
172              
173             =head1 ATTRIBUTES
174              
175             =head2 value
176              
177             The cookie's value.
178              
179             (Note that cookie objects use overloading to stringify to their value, so if
180             you say e.g. return "Hi, $cookie", you'll get the cookie's value there.)
181              
182             In list context, returns a list of potentially multiple values; in scalar
183             context, returns just the first value. (So, if you expect a cookie to have
184             multiple values, use list context.)
185              
186             =head2 name
187              
188             The cookie's name.
189              
190             =head2 expires
191              
192             The cookie's expiration date. There are several formats.
193              
194             Unix epoch time like 1288817656 to mean "Wed, 03-Nov-2010 20:54:16 GMT"
195              
196             It also supports a human readable offset from the current time such as "2 hours".
197             See the documentation of L<Dancer2::Core::Time> for details of all supported
198             formats.
199              
200             =head2 domain
201              
202             The cookie's domain.
203              
204             =head2 path
205              
206             The cookie's path.
207              
208             =head2 secure
209              
210             If true, it instructs the client to only serve the cookie over secure
211             connections such as https.
212              
213             =head2 http_only
214              
215             By default, cookies are created with a property, named C<HttpOnly>,
216             that can be used for security, forcing the cookie to be used only by
217             the server (via HTTP) and not by any JavaScript code.
218              
219             If your cookie is meant to be used by some JavaScript code, set this
220             attribute to 0.
221              
222             =head2 same_site
223              
224             Whether the cookie ought not to be sent along with cross-site requests.
225             Valid values are C<Strict>, C<Lax>, or C<None>. Default is unset.
226             Refer to
227             L<RFC6265bis|https://tools.ietf.org/html/draft-ietf-httpbis-cookie-same-site>
228             for further details regarding same-site context.
229              
230             =head1 METHODS
231              
232             =head2 my $cookie=Dancer2::Core::Cookie->new(%opts);
233              
234             Create a new Dancer2::Core::Cookie object.
235              
236             You can set any attribute described in the I<ATTRIBUTES> section above.
237              
238             =head2 my $header=$cookie->to_header();
239              
240             Creates a proper HTTP cookie header from the content.
241              
242             =head1 AUTHOR
243              
244             Dancer Core Developers
245              
246             =head1 COPYRIGHT AND LICENSE
247              
248             This software is copyright (c) 2023 by Alexis Sukrieh.
249              
250             This is free software; you can redistribute it and/or modify it under
251             the same terms as the Perl 5 programming language system itself.
252              
253             =cut