summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrédéric Buclin <LpSolit@gmail.com>2012-04-17 20:56:41 +0200
committerFrédéric Buclin <LpSolit@gmail.com>2012-04-17 20:56:41 +0200
commit9a5a196d79ed8692c45595c4e3d42e34571bc3a7 (patch)
tree058a2aba35e324354547f7d45e504282b3eb98a5
parent3b2fcf526e02c1d74f88b567083a9be371d5a607 (diff)
downloadbugzilla-9a5a196d79ed8692c45595c4e3d42e34571bc3a7.tar.gz
bugzilla-9a5a196d79ed8692c45595c4e3d42e34571bc3a7.tar.xz
Bug 745197: Add a hook in Bugzilla::Error::_throw_error() so that extensions can control the way to throw errors
r=dkl a=LpSolit
-rw-r--r--Bugzilla/Error.pm91
-rw-r--r--Bugzilla/Hook.pm31
-rw-r--r--extensions/Example/Extension.pm19
-rw-r--r--template/en/default/global/code-error.html.tmpl6
4 files changed, 100 insertions, 47 deletions
diff --git a/Bugzilla/Error.pm b/Bugzilla/Error.pm
index ebe8decbd..e1df5ddbb 100644
--- a/Bugzilla/Error.pm
+++ b/Bugzilla/Error.pm
@@ -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;
diff --git a/Bugzilla/Hook.pm b/Bugzilla/Hook.pm
index 8eac561c0..27184c2e4 100644
--- a/Bugzilla/Hook.pm
+++ b/Bugzilla/Hook.pm
@@ -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
diff --git a/extensions/Example/Extension.pm b/extensions/Example/Extension.pm
index 5cd6a1d29..62fb345d9 100644
--- a/extensions/Example/Extension.pm
+++ b/extensions/Example/Extension.pm
@@ -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) = @_;
diff --git a/template/en/default/global/code-error.html.tmpl b/template/en/default/global/code-error.html.tmpl
index 4a4720b2a..19d062841 100644
--- a/template/en/default/global/code-error.html.tmpl
+++ b/template/en/default/global/code-error.html.tmpl
@@ -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>