diff --git a/lib/Mojolicious/Sessions.pm b/lib/Mojolicious/Sessions.pm index 6056105fa1..989ad5faaa 100644 --- a/lib/Mojolicious/Sessions.pm +++ b/lib/Mojolicious/Sessions.pm @@ -8,9 +8,9 @@ has [qw(cookie_domain secure)]; has cookie_name => 'mojolicious'; has cookie_path => '/'; has default_expiration => 3600; -has deserialize => sub { \&Mojo::JSON::j }; +has deserialize => sub { \&_deserialize }; has samesite => 'Lax'; -has serialize => sub { \&Mojo::JSON::encode_json }; +has serialize => sub { \&_serialize }; sub load { my ($self, $c) = @_; @@ -61,6 +61,14 @@ sub store { $c->signed_cookie($self->cookie_name, $value, $options); } +sub _deserialize { Mojo::JSON::decode_json($_[0] =~ s/\}\KZ*$//r) } + +sub _serialize { + no warnings 'numeric'; + my $out = Mojo::JSON::encode_json($_[0]); + return $out . 'Z' x (1025 - length $out); +} + 1; =encoding utf8 diff --git a/t/mojolicious/lite_app.t b/t/mojolicious/lite_app.t index 31b3037ca4..ddf1967024 100644 --- a/t/mojolicious/lite_app.t +++ b/t/mojolicious/lite_app.t @@ -274,6 +274,12 @@ get '/session_cookie/2' => sub { $c->render(text => "Session is $value!"); }; +get '/session_length' => sub { + my $c = shift; + $c->session->{q} = $c->param('q'); + $c->rendered(204); +}; + get '/foo' => sub { my $c = shift; $c->render(text => 'Yea baby!'); @@ -799,6 +805,30 @@ ok !$t->tx, 'session reset'; $t->get_ok('/session_cookie/2')->status_is(200)->header_is(Server => 'Mojolicious (Perl)') ->content_is('Session is missing!'); + +subtest 'Session length' => sub { + my $extract = sub { + my $value = $_[0]->tx->res->cookie('mojolicious')->value; + $value =~ s/--([^\-]+)$//; + $value =~ y/=/-/; + return Mojo::Util::b64_decode($value); + }; + + subtest 'Short session' => sub { + $t->reset_session; + my $value = $t->get_ok('/session_length?q=a')->status_is(204)->$extract; + cmp_ok length($value), '>', 1024, 'session is long enough'; + ok $value =~ /Z+$/, 'session is padded'; + }; + + subtest 'Long session' => sub { + $t->reset_session; + my $value = $t->get_ok('/session_length?q=' . 'a' x 1025)->status_is(204)->$extract; + cmp_ok length($value), '>', 1024, 'session is long enough'; + ok $value !~ /Z+$/, 'session is not padded'; + }; +}; + # Text $t->get_ok('/foo')->status_is(200)->header_is(Server => 'Mojolicious (Perl)')->content_is('Yea baby!');