From 2f6ce468986698fbbbb83b563a14b5cf89b78008 Mon Sep 17 00:00:00 2001 From: Andy Beverley Date: Thu, 27 Jun 2024 22:42:53 +0100 Subject: [PATCH 1/2] Fix unable to use send_as during template processing (#1712) --- lib/Dancer2/Core/App.pm | 12 +++++- t/issues/gh-1712/gh-1712.t | 70 ++++++++++++++++++++++++++++++++++ t/issues/gh-1712/views/exec.tt | 1 + 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 t/issues/gh-1712/gh-1712.t create mode 100644 t/issues/gh-1712/views/exec.tt diff --git a/lib/Dancer2/Core/App.pm b/lib/Dancer2/Core/App.pm index 947824fb4..34c2a7387 100644 --- a/lib/Dancer2/Core/App.pm +++ b/lib/Dancer2/Core/App.pm @@ -896,10 +896,16 @@ sub template { $self->set_with_return( sub { $local_response ||= shift; }); - my $content = $template->process( @_ ); + # Catch any exceptions that may happen during template processing + my $content = eval { $template->process( @_ ) }; $self->set_with_return($old_with_return); + # If there was a previous response set before the exception (or set as + # part of the exception handling), then use that, otherwise throw the + # exception as normal if ($local_response) { $self->with_return->($local_response); + } elsif ($@) { + die $@; } return $content; } @@ -972,7 +978,9 @@ sub send_as { $options->{charset} = $self->config->{charset} || 'UTF-8'; my $content = Encode::encode( $options->{charset}, $data ); $options->{content_type} ||= join '/', 'text', lc $type; - $self->send_file( \$content, %$options ); # returns from sub + # Explicit return needed here, as if we are currently rendering a + # template then with_return will not longjump + return $self->send_file( \$content, %$options ); } # Try and load the serializer class diff --git a/t/issues/gh-1712/gh-1712.t b/t/issues/gh-1712/gh-1712.t new file mode 100644 index 000000000..dc12ac80b --- /dev/null +++ b/t/issues/gh-1712/gh-1712.t @@ -0,0 +1,70 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More; +use Plack::Test; +use HTTP::Request::Common; +use Ref::Util qw; + +# Tests for obscure rendering situations that may occur whilst undertaking +# template processing + +{ + package MyApp; + + use Dancer2; + + set template => 'template_toolkit'; + + hook on_route_exception => sub { + status 200; + send_as(plain => "Some plain text"); + }; + + get '/bork' => sub { + my $bork = sub { + die "I've borked in the template"; + }; + template 'exec', + { exec_sub => $bork } + }; + + get '/plain' => sub { + my $plain = sub { + send_as(plain => "Some plain text"); + }; + template 'exec', + { exec_sub => $plain } + }; + + get '/html' => sub { + my $html = sub { + send_as(html => "

HTML text

"); + }; + template 'exec', + { exec_sub => $html } + }; +} + +my $app = Dancer2->psgi_app; +ok( is_coderef($app), 'Got app' ); + +test_psgi $app, sub { + my $cb = shift; + + my $res = $cb->(GET '/bork'); + is $res->code, 200, 'Correct status code when overriding exception handling'; + like $res->content, qr/plain text/, 'Correct content when overriding exception handling'; + + $res = $cb->(GET '/plain'); + is $res->code, 200, 'Correct status when sending as plain during template render'; + like $res->content, qr/plain text/, 'Correct content when sending as plain'; + + $res = $cb->(GET '/html'); + is $res->code, 200, 'Correct status when sending as HTML during template render'; + like $res->content, qr/HTML text/, 'Correct content when sending as HTML'; +}; + +done_testing(); diff --git a/t/issues/gh-1712/views/exec.tt b/t/issues/gh-1712/views/exec.tt new file mode 100644 index 000000000..1de130f72 --- /dev/null +++ b/t/issues/gh-1712/views/exec.tt @@ -0,0 +1 @@ +[% IF NOT exec_sub %]foobar[% END %] From b36481f26e6e772612a97adcb37d656652e72dc1 Mon Sep 17 00:00:00 2001 From: Andy Beverley Date: Mon, 8 Jul 2024 12:10:44 +0100 Subject: [PATCH 2/2] Ensure $@ is not overwritten --- lib/Dancer2/Core/App.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Dancer2/Core/App.pm b/lib/Dancer2/Core/App.pm index 34c2a7387..3aa1cff51 100644 --- a/lib/Dancer2/Core/App.pm +++ b/lib/Dancer2/Core/App.pm @@ -898,14 +898,15 @@ sub template { }); # Catch any exceptions that may happen during template processing my $content = eval { $template->process( @_ ) }; + my $eval_result = $@; $self->set_with_return($old_with_return); # If there was a previous response set before the exception (or set as # part of the exception handling), then use that, otherwise throw the # exception as normal if ($local_response) { $self->with_return->($local_response); - } elsif ($@) { - die $@; + } elsif ($eval_result) { + die $eval_result; } return $content; }