Commit 9a5a196d authored by Frédéric Buclin's avatar Frédéric Buclin

Bug 745197: Add a hook in Bugzilla::Error::_throw_error() so that extensions can…

Bug 745197: Add a hook in Bugzilla::Error::_throw_error() so that extensions can control the way to throw errors r=dkl a=LpSolit
parent 3b2fcf52
......@@ -77,56 +77,61 @@ sub _throw_error {
}
my $template = Bugzilla->template;
if (Bugzilla->error_mode == ERROR_MODE_WEBPAGE) {
print Bugzilla->cgi->header();
$template->process($name, $vars)
|| ThrowTemplateError($template->error());
}
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) {
print Bugzilla->cgi->header();
print $message;
}
elsif (Bugzilla->error_mode == ERROR_MODE_TEST) {
die Dumper($vars);
}
else {
my $message;
$template->process($name, $vars, \$message)
|| ThrowTemplateError($template->error());
if (Bugzilla->error_mode == ERROR_MODE_DIE) {
die("$message\n");
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)
{
# 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);
}
elsif (Bugzilla->error_mode == ERROR_MODE_DIE_SOAP_FAULT
|| Bugzilla->error_mode == ERROR_MODE_JSON_RPC)
{
# 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;
# 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,
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;
# 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,
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;
......
......@@ -687,6 +687,37 @@ Params:
=back
=head2 error_catch
This hook allows extensions to catch errors thrown by Bugzilla and
take the appropriate actions.
Params:
=over
=item C<error>
A string representing the error code thrown by Bugzilla. This string
matches the C<error> variable in C<global/user-error.html.tmpl> and
C<global/code-error.html.tmpl>.
=item C<message>
If the error mode is set to C<ERROR_MODE_WEBPAGE>, you get a reference to
the whole HTML page with the error message in it, including its header and
footer. If you need to extract the error message itself, you can do it by
looking at the content of the table cell whose ID is C<error_msg>.
If the error mode is not set to C<ERROR_MODE_WEBPAGE>, you get a reference
to the error message itself.
=item C<vars>
This hash contains all the data passed to the error template. Its content
depends on the error thrown.
=back
=head2 flag_end_of_update
This happens at the end of L<Bugzilla::Flag/update_flags>, after all other
......
......@@ -340,6 +340,25 @@ sub enter_bug_entrydefaultvars {
$vars->{'example'} = 1;
}
sub error_catch {
my ($self, $args) = @_;
# Customize the error message displayed when someone tries to access
# page.cgi with an invalid page ID, and keep track of this attempt
# in the web server log.
return unless Bugzilla->error_mode == ERROR_MODE_WEBPAGE;
return unless $args->{error} eq 'bad_page_cgi_id';
my $page_id = $args->{vars}->{page_id};
my $login = Bugzilla->user->identity || "Someone";
warn "$login attempted to access page.cgi with id = $page_id";
my $page = $args->{message};
my $new_error_msg = "Ah ah, you tried to access $page_id? Good try!";
$new_error_msg = html_quote($new_error_msg);
# There are better tools to parse an HTML page, but it's just an example.
$$page =~ s/(?<=<td id="error_msg" class="throw_error">).*(?=<\/td>)/$new_error_msg/si;
}
sub flag_end_of_update {
my ($self, $args) = @_;
......
......@@ -508,10 +508,8 @@
<table cellpadding="20">
<tr>
<td bgcolor="#ff0000">
<font size="+2">
[% error_message FILTER none %]
</font>
<td id="error_msg" class="throw_error">
[% error_message FILTER none %]
</td>
</tr>
</table>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment