aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/Error.pm')
-rw-r--r--Bugzilla/Error.pm303
1 files changed, 156 insertions, 147 deletions
diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm
index ef6320d15..ac56b9b02 100644
--- a/Bugzilla/Error.pm
+++ b/Bugzilla/Error.pm
@@ -26,176 +26,185 @@ use Date::Format;
# 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!
sub _in_eval {
- my $in_eval = 0;
- for (my $stack = 1; my $sub = (caller($stack))[3]; $stack++) {
- last if $sub =~ /^ModPerl/;
- $in_eval = 1 if $sub =~ /^\(eval\)/;
- }
- return $in_eval;
+ my $in_eval = 0;
+ for (my $stack = 1; my $sub = (caller($stack))[3]; $stack++) {
+ last if $sub =~ /^ModPerl/;
+ $in_eval = 1 if $sub =~ /^\(eval\)/;
+ }
+ return $in_eval;
}
sub _throw_error {
- my ($name, $error, $vars) = @_;
- my $dbh = Bugzilla->dbh;
- $vars ||= {};
-
- $vars->{error} = $error;
-
- # Make sure any transaction is rolled back (if supported).
- # If we are within an eval(), do not roll back transactions as we are
- # eval'uating some test on purpose.
- $dbh->bz_rollback_transaction() if ($dbh->bz_in_transaction() && !_in_eval());
-
- my $datadir = bz_locations()->{'datadir'};
- # If a writable $datadir/errorlog exists, log error details there.
- if (-w "$datadir/errorlog") {
- require Bugzilla::Util;
- require Data::Dumper;
- my $mesg = "";
- for (1..75) { $mesg .= "-"; };
- $mesg .= "\n[$$] " . time2str("%D %H:%M:%S ", time());
- $mesg .= "$name $error ";
- $mesg .= Bugzilla::Util::remote_ip();
- $mesg .= Bugzilla->user->login;
- $mesg .= (' actually ' . Bugzilla->sudoer->login) if Bugzilla->sudoer;
- $mesg .= "\n";
- my %params = Bugzilla->cgi->Vars;
- $Data::Dumper::Useqq = 1;
- for my $param (sort keys %params) {
- my $val = $params{$param};
- # obscure passwords
- $val = "*****" if $param =~ /password/i;
- # limit line length
- $val =~ s/^(.{512}).*$/$1\[CHOP\]/;
- $mesg .= "[$$] " . Data::Dumper->Dump([$val],["param($param)"]);
- }
- for my $var (sort keys %ENV) {
- my $val = $ENV{$var};
- $val = "*****" if $val =~ /password|http_pass/i;
- $mesg .= "[$$] " . Data::Dumper->Dump([$val],["env($var)"]);
- }
- open(ERRORLOGFID, ">>", "$datadir/errorlog");
- print ERRORLOGFID "$mesg\n";
- close ERRORLOGFID;
- }
-
- my $template = Bugzilla->template;
- my $message;
- # 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) {
- $template->process($name, $vars, \$message)
- || ThrowTemplateError($template->error());
+ my ($name, $error, $vars) = @_;
+ my $dbh = Bugzilla->dbh;
+ $vars ||= {};
+
+ $vars->{error} = $error;
+
+ # Make sure any transaction is rolled back (if supported).
+ # If we are within an eval(), do not roll back transactions as we are
+ # eval'uating some test on purpose.
+ $dbh->bz_rollback_transaction() if ($dbh->bz_in_transaction() && !_in_eval());
+
+ my $datadir = bz_locations()->{'datadir'};
+
+ # If a writable $datadir/errorlog exists, log error details there.
+ if (-w "$datadir/errorlog") {
+ require Bugzilla::Util;
+ require Data::Dumper;
+ my $mesg = "";
+ for (1 .. 75) { $mesg .= "-"; }
+ $mesg .= "\n[$$] " . time2str("%D %H:%M:%S ", time());
+ $mesg .= "$name $error ";
+ $mesg .= Bugzilla::Util::remote_ip();
+ $mesg .= Bugzilla->user->login;
+ $mesg .= (' actually ' . Bugzilla->sudoer->login) if Bugzilla->sudoer;
+ $mesg .= "\n";
+ my %params = Bugzilla->cgi->Vars;
+ $Data::Dumper::Useqq = 1;
+
+ for my $param (sort keys %params) {
+ my $val = $params{$param};
+
+ # obscure passwords
+ $val = "*****" if $param =~ /password/i;
+
+ # limit line length
+ $val =~ s/^(.{512}).*$/$1\[CHOP\]/;
+ $mesg .= "[$$] " . Data::Dumper->Dump([$val], ["param($param)"]);
}
-
- # Let's call the hook first, so that extensions can override
- # or extend the default behavior, or add their own error codes.
- Bugzilla::Hook::process('error_catch', { error => $error, vars => $vars,
- message => \$message });
-
- if (Bugzilla->error_mode == ERROR_MODE_WEBPAGE) {
- my $cgi = Bugzilla->cgi;
- $cgi->close_standby_message('text/html', 'inline', 'error', 'html');
- print $message;
- print $cgi->multipart_final() if $cgi->{_multipart_in_progress};
+ for my $var (sort keys %ENV) {
+ my $val = $ENV{$var};
+ $val = "*****" if $val =~ /password|http_pass/i;
+ $mesg .= "[$$] " . Data::Dumper->Dump([$val], ["env($var)"]);
}
- elsif (Bugzilla->error_mode == ERROR_MODE_TEST) {
- die Dumper($vars);
+ open(ERRORLOGFID, ">>", "$datadir/errorlog");
+ print ERRORLOGFID "$mesg\n";
+ close ERRORLOGFID;
+ }
+
+ my $template = Bugzilla->template;
+ my $message;
+
+ # 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) {
+ $template->process($name, $vars, \$message)
+ || ThrowTemplateError($template->error());
+ }
+
+ # Let's call the hook first, so that extensions can override
+ # or extend the default behavior, or add their own error codes.
+ Bugzilla::Hook::process('error_catch',
+ {error => $error, vars => $vars, message => \$message});
+
+ if (Bugzilla->error_mode == ERROR_MODE_WEBPAGE) {
+ my $cgi = Bugzilla->cgi;
+ $cgi->close_standby_message('text/html', 'inline', 'error', 'html');
+ print $message;
+ print $cgi->multipart_final() if $cgi->{_multipart_in_progress};
+ }
+ elsif (Bugzilla->error_mode == ERROR_MODE_TEST) {
+ die Dumper($vars);
+ }
+ elsif (Bugzilla->error_mode == ERROR_MODE_DIE) {
+ die("$message\n");
+ }
+ elsif (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT
+ || Bugzilla->error_mode == ERROR_MODE_JSON_RPC
+ || Bugzilla->error_mode == ERROR_MODE_REST)
+ {
+ # Clone the hash so we aren't modifying the constant.
+ my %error_map = %{WS_ERROR_CODE()};
+ Bugzilla::Hook::process('webservice_error_codes', {error_map => \%error_map});
+ my $code = $error_map{$error};
+ if (!$code) {
+ $code = ERROR_UNKNOWN_FATAL if $name =~ /code/i;
+ $code = ERROR_UNKNOWN_TRANSIENT if $name =~ /user/i;
}
- elsif (Bugzilla->error_mode == ERROR_MODE_DIE) {
- die("$message\n");
+
+ if (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT) {
+ die SOAP::Fault->faultcode($code)->faultstring($message);
}
- elsif (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT
- || Bugzilla->error_mode == ERROR_MODE_JSON_RPC
- || Bugzilla->error_mode == ERROR_MODE_REST)
- {
- # Clone the hash so we aren't modifying the constant.
- my %error_map = %{ WS_ERROR_CODE() };
- Bugzilla::Hook::process('webservice_error_codes',
- { error_map => \%error_map });
- my $code = $error_map{$error};
- if (!$code) {
- $code = ERROR_UNKNOWN_FATAL if $name =~ /code/i;
- $code = ERROR_UNKNOWN_TRANSIENT if $name =~ /user/i;
- }
-
- if (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT) {
- die SOAP::Fault->faultcode($code)->faultstring($message);
- }
- else {
- my $server = Bugzilla->_json_server;
-
- my $status_code = 0;
- if (Bugzilla->error_mode == ERROR_MODE_REST) {
- my %status_code_map = %{ REST_STATUS_CODE_MAP() };
- $status_code = $status_code_map{$code} || $status_code_map{'_default'};
- }
- # Technically JSON-RPC isn't allowed to have error numbers
- # higher than 999, but we do this to avoid conflicts with
- # the internal JSON::RPC error codes.
- $server->raise_error(code => 100000 + $code,
- status_code => $status_code,
- message => $message,
- id => $server->{_bz_request_id},
- version => $server->version);
- # Most JSON-RPC Throw*Error calls happen within an eval inside
- # of JSON::RPC. So, in that circumstance, instead of exiting,
- # we die with no message. JSON::RPC checks raise_error before
- # it checks $@, so it returns the proper error.
- die if _in_eval();
- $server->response($server->error_response_header);
- }
+ else {
+ my $server = Bugzilla->_json_server;
+
+ my $status_code = 0;
+ if (Bugzilla->error_mode == ERROR_MODE_REST) {
+ my %status_code_map = %{REST_STATUS_CODE_MAP()};
+ $status_code = $status_code_map{$code} || $status_code_map{'_default'};
+ }
+
+ # Technically JSON-RPC isn't allowed to have error numbers
+ # higher than 999, but we do this to avoid conflicts with
+ # the internal JSON::RPC error codes.
+ $server->raise_error(
+ code => 100000 + $code,
+ status_code => $status_code,
+ message => $message,
+ id => $server->{_bz_request_id},
+ version => $server->version
+ );
+
+ # Most JSON-RPC Throw*Error calls happen within an eval inside
+ # of JSON::RPC. So, in that circumstance, instead of exiting,
+ # we die with no message. JSON::RPC checks raise_error before
+ # it checks $@, so it returns the proper error.
+ die if _in_eval();
+ $server->response($server->error_response_header);
}
- exit;
+ }
+ exit;
}
sub ThrowUserError {
- _throw_error("global/user-error.html.tmpl", @_);
+ _throw_error("global/user-error.html.tmpl", @_);
}
sub ThrowCodeError {
- my (undef, $vars) = @_;
+ my (undef, $vars) = @_;
+
+ # Don't show function arguments, in case they contain
+ # confidential data.
+ local $Carp::MaxArgNums = -1;
- # Don't show function arguments, in case they contain
- # confidential data.
- local $Carp::MaxArgNums = -1;
- # 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();
+ # 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();
- _throw_error("global/code-error.html.tmpl", @_);
+ _throw_error("global/code-error.html.tmpl", @_);
}
sub ThrowTemplateError {
- my ($template_err) = @_;
- my $dbh = Bugzilla->dbh;
+ my ($template_err) = @_;
+ my $dbh = Bugzilla->dbh;
- # Make sure the transaction is rolled back (if supported).
- $dbh->bz_rollback_transaction() if $dbh->bz_in_transaction();
+ # Make sure the transaction is rolled back (if supported).
+ $dbh->bz_rollback_transaction() if $dbh->bz_in_transaction();
- my $vars = {};
- if (Bugzilla->error_mode == ERROR_MODE_DIE) {
- die("error: template error: $template_err");
- }
+ my $vars = {};
+ if (Bugzilla->error_mode == ERROR_MODE_DIE) {
+ die("error: template error: $template_err");
+ }
- $vars->{'template_error_msg'} = $template_err;
- $vars->{'error'} = "template_error";
+ $vars->{'template_error_msg'} = $template_err;
+ $vars->{'error'} = "template_error";
- my $template = Bugzilla->template;
+ my $template = Bugzilla->template;
- # Try a template first; but if this one fails too, fall back
- # on plain old print statements.
- if (!$template->process("global/code-error.html.tmpl", $vars)) {
- require Bugzilla::Util;
- import Bugzilla::Util qw(html_quote);
- my $maintainer = Bugzilla->params->{'maintainer'};
- my $error = html_quote($vars->{'template_error_msg'});
- my $error2 = html_quote($template->error());
- my $url = html_quote(Bugzilla->cgi->self_url);
+ # Try a template first; but if this one fails too, fall back
+ # on plain old print statements.
+ if (!$template->process("global/code-error.html.tmpl", $vars)) {
+ require Bugzilla::Util;
+ import Bugzilla::Util qw(html_quote);
+ my $maintainer = Bugzilla->params->{'maintainer'};
+ my $error = html_quote($vars->{'template_error_msg'});
+ my $error2 = html_quote($template->error());
+ my $url = html_quote(Bugzilla->cgi->self_url);
- print <<END;
+ print <<END;
<p>
Bugzilla has suffered an internal error. Please save this page and
send it to $maintainer with details of what you were doing at the
@@ -206,8 +215,8 @@ sub ThrowTemplateError {
First error: $error<br>
Second error: $error2</p>
END
- }
- exit;
+ }
+ exit;
}
1;