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