Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7130b77

Browse files
committedNov 25, 2024·
Add partitioned cookies
1 parent 2376b90 commit 7130b77

File tree

3 files changed

+46
-11
lines changed

3 files changed

+46
-11
lines changed
 

‎lib/Mojo/Cookie/Response.pm

+14-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use Mojo::Base 'Mojo::Cookie';
44
use Mojo::Date;
55
use Mojo::Util qw(quote split_cookie_header);
66

7-
has [qw(domain expires host_only httponly max_age path samesite secure)];
7+
has [qw(domain expires host_only httponly max_age partitioned path samesite secure)];
88

9-
my %ATTRS = map { $_ => 1 } qw(domain expires httponly max-age path samesite secure);
9+
my %ATTRS = map { $_ => 1 } qw(domain expires httponly max-age partitioned path samesite secure);
1010

1111
sub parse {
1212
my ($self, $str) = @_;
@@ -21,7 +21,7 @@ sub parse {
2121
next unless $ATTRS{my $attr = lc $name};
2222
$value =~ s/^\.// if $attr eq 'domain' && defined $value;
2323
$value = Mojo::Date->new($value // '')->epoch if $attr eq 'expires';
24-
$value = 1 if $attr eq 'secure' || $attr eq 'httponly';
24+
$value = 1 if $attr eq 'secure' || $attr eq 'httponly' || $attr eq 'partitioned';
2525
$cookies[-1]{$attr eq 'max-age' ? 'max_age' : $attr} = $value;
2626
}
2727
}
@@ -47,6 +47,9 @@ sub to_string {
4747
# "path"
4848
if (my $path = $self->path) { $cookie .= "; path=$path" }
4949

50+
# "Partitioned"
51+
$cookie .= "; Partitioned" if $self->partitioned;
52+
5053
# "secure"
5154
$cookie .= "; secure" if $self->secure;
5255

@@ -123,6 +126,14 @@ HttpOnly flag, which can prevent client-side scripts from accessing this cookie.
123126
124127
Max age for cookie.
125128
129+
=head2 partitioned
130+
131+
my $partitioned = $cookie->partitioned;
132+
$cookie = $cookie->parititoned(1);
133+
134+
Partitioned flag, this is to be used in accordance to the L<CHIPS ammendment
135+
to RFC 6265|https://www.ietf.org/archive/id/draft-cutler-httpbis-partitioned-cookies-00.html>.
136+
126137
=head2 path
127138
128139
my $path = $cookie->path;

‎lib/Mojolicious/Sessions.pm

+18-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use Mojo::Base -base;
44
use Mojo::JSON;
55
use Mojo::Util qw(b64_decode b64_encode);
66

7-
has [qw(cookie_domain encrypted secure)];
7+
has [qw(cookie_domain encrypted partitioned secure)];
88
has cookie_name => 'mojolicious';
99
has cookie_path => '/';
1010
has default_expiration => 3600;
@@ -52,12 +52,13 @@ sub store {
5252
my $value = b64_encode $self->serialize->($session), '';
5353
$value =~ y/=/-/;
5454
my $options = {
55-
domain => $self->cookie_domain,
56-
expires => $session->{expires},
57-
httponly => 1,
58-
path => $self->cookie_path,
59-
samesite => $self->samesite,
60-
secure => $self->secure
55+
domain => $self->cookie_domain,
56+
expires => $session->{expires},
57+
httponly => 1,
58+
partitioned => $self->partitioned,
59+
path => $self->cookie_path,
60+
samesite => $self->samesite,
61+
secure => $self->secure,
6162
};
6263
my $method = $self->encrypted ? 'encrypted_cookie' : 'signed_cookie';
6364
$c->$method($self->cookie_name, $value, $options);
@@ -150,6 +151,16 @@ A callback used to deserialize sessions, defaults to L<Mojo::JSON/"j">.
150151
Use encrypted session cookies instead of merely cryptographically signed ones. Note that this attribute is
151152
B<EXPERIMENTAL> and might change without warning!
152153
154+
=head2 partitioned
155+
156+
my $bool = $sessions->partitioned;
157+
$sessions = $sessions->partitioned($bool);
158+
159+
Set the partitioned flag on all session cookies, this is used in accordance to the L<CHIPS ammendment to
160+
RFC 6265|https://www.ietf.org/archive/id/draft-cutler-httpbis-partitioned-cookies-00.html>.
161+
162+
Partitioned cookies are held within a separate cookie jar per top-level site.
163+
153164
=head2 samesite
154165
155166
my $samesite = $sessions->samesite;

‎t/mojo/cookie.t

+14-1
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,14 @@ subtest 'Full response cookie as string' => sub {
168168
$cookie->value('ba r');
169169
$cookie->domain('example.com');
170170
$cookie->path('/test');
171+
$cookie->partitioned(1);
171172
$cookie->max_age(60);
172173
$cookie->expires(1218092879);
173174
$cookie->secure(1);
174175
$cookie->httponly(1);
175176
$cookie->samesite('Lax');
176177
is $cookie->to_string, '0="ba r"; expires=Thu, 07 Aug 2008 07:07:59 GMT; domain=example.com;'
177-
. ' path=/test; secure; HttpOnly; SameSite=Lax; Max-Age=60', 'right format';
178+
. ' path=/test; Partitioned; secure; HttpOnly; SameSite=Lax; Max-Age=60', 'right format';
178179
};
179180

180181
subtest 'Empty response cookie' => sub {
@@ -216,6 +217,18 @@ subtest 'Parse response cookie (RFC 6265)' => sub {
216217
is $cookies->[1], undef, 'no more cookies';
217218
};
218219

220+
subtest 'Partitioned cookie (RFC 6265 CHIPS)' => sub {
221+
my $cookies
222+
= Mojo::Cookie::Response->parse(
223+
'foo="bar"; Domain=example.com; Partitioned; Path=/test; Max-Age=60; Expires=Thu, 07 Aug 2008 07:07:59 GMT; Secure;'
224+
);
225+
is $cookies->[0]->partitioned, 1, 'partitioned set?';
226+
227+
$cookies = Mojo::Cookie::Response->parse(
228+
'foo="bar"; Domain=example.com; Path=/test; Max-Age=60; Expires=Thu, 07 Aug 2008 07:07:59 GMT; Secure;');
229+
is $cookies->[0]->partitioned, undef, 'partitioned not set?';
230+
};
231+
219232
subtest 'Parse response cookie with invalid flag (RFC 6265)' => sub {
220233
my $cookies = Mojo::Cookie::Response->parse(
221234
'foo="ba r"; Domain=.example.com; Path=/test; Max-Age=60;' . ' Expires=Thu, 07 Aug 2008 07:07:59 GMT; InSecure;');

0 commit comments

Comments
 (0)
Please sign in to comment.