From dacce0f73894bae5b7c4df2594ca4dd48dfeec0d Mon Sep 17 00:00:00 2001 From: Dylan Hardison Date: Fri, 22 Apr 2016 11:56:44 -0400 Subject: Bug 1195736 - intermittent internal error: "file error - nav_link: not found" (also manifests as fields_lhs: not found) --- Bugzilla/Error.pm | 21 ++++++++++++++++++--- Bugzilla/Sentry.pm | 1 + Bugzilla/Template.pm | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) (limited to 'Bugzilla') diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm index fa898fba4..e619f3f84 100644 --- a/Bugzilla/Error.pm +++ b/Bugzilla/Error.pm @@ -36,6 +36,7 @@ use Bugzilla::Util; use Carp; use Data::Dumper; use Date::Format; +use Scalar::Util qw(blessed); # We cannot use $^S to detect if we are in an eval(), because mod_perl # already eval'uates everything, so $^S = 1 in all cases under mod_perl! @@ -98,7 +99,7 @@ sub _throw_error { # There are some tests that throw and catch a lot of errors, # and calling $template->process over and over for those errors # is too slow. So instead, we just "die" with a dump of the arguments. - if (Bugzilla->error_mode != ERROR_MODE_TEST) { + if (Bugzilla->error_mode != ERROR_MODE_TEST && !$Bugzilla::Template::is_processing) { $template->process($name, $vars, \$message) || ThrowTemplateError($template->error()); } @@ -109,6 +110,12 @@ sub _throw_error { Bugzilla::Hook::process('error_catch', { error => $error, vars => $vars, message => \$message }); + if ($Bugzilla::Template::is_processing) { + $name =~ /^global\/(user|code)-error/; + my $type = $1 // 'unknown'; + die Template::Exception->new("bugzilla.$type.$error", $vars); + } + if (Bugzilla->error_mode == ERROR_MODE_WEBPAGE) { if (sentry_should_notify($vars->{error})) { $vars->{maintainers_notified} = 1; @@ -174,9 +181,9 @@ sub _throw_error { $server->response($server->error_response_header); } } + exit; } - sub ThrowUserError { _throw_error("global/user-error.html.tmpl", @_); } @@ -190,7 +197,7 @@ sub ThrowCodeError { # Don't show the error as coming from Bugzilla::Error, show it # as coming from the caller. local $Carp::CarpInternal{'Bugzilla::Error'} = 1; - $vars->{traceback} = Carp::longmess(); + $vars->{traceback} //= Carp::longmess(); _throw_error("global/code-error.html.tmpl", @_); } @@ -202,6 +209,14 @@ sub ThrowTemplateError { # Make sure the transaction is rolled back (if supported). $dbh->bz_rollback_transaction() if $dbh->bz_in_transaction(); + if (blessed($template_err) && $template_err->isa('Template::Exception')) { + my $type = $template_err->type; + if ($type =~ /^bugzilla\.(code|user)\.(.+)/) { + _throw_error("global/$1-error.html.tmpl", $2, $template_err->info); + return; + } + } + my $vars = {}; if (Bugzilla->error_mode == ERROR_MODE_DIE) { die("error: template error: $template_err"); diff --git a/Bugzilla/Sentry.pm b/Bugzilla/Sentry.pm index d49eb0808..e2fdcad99 100644 --- a/Bugzilla/Sentry.pm +++ b/Bugzilla/Sentry.pm @@ -321,6 +321,7 @@ sub _sentry_die_handler { $in_cgi_carp_die = 1 if $sub =~ /CGI::Carp::die$/; } + return if $Bugzilla::Template::is_processing; return if _in_eval(); # mod_perl overrides exit to call die with this string diff --git a/Bugzilla/Template.pm b/Bugzilla/Template.pm index 56ebd9c21..343753d46 100644 --- a/Bugzilla/Template.pm +++ b/Bugzilla/Template.pm @@ -665,12 +665,15 @@ $Template::Stash::SCALAR_OPS->{ truncate } = ############################################################################### +our $is_processing = 0; + sub process { my $self = shift; # All of this current_langs stuff allows template_inner to correctly # determine what-language Template object it should instantiate. my $current_langs = Bugzilla->request_cache->{template_current_lang} ||= []; unshift(@$current_langs, $self->context->{bz_language}); + local $is_processing = 1; my $retval = $self->SUPER::process(@_); shift @$current_langs; return $retval; -- cgit v1.2.3-24-g4f1b