]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 745197: Add a hook in Bugzilla::Error::_throw_error() so that extensions can...
authorFrédéric Buclin <LpSolit@gmail.com>
Tue, 17 Apr 2012 19:11:20 +0000 (21:11 +0200)
committerFrédéric Buclin <LpSolit@gmail.com>
Tue, 17 Apr 2012 19:11:20 +0000 (21:11 +0200)
r=dkl a=LpSolit

Bugzilla/Error.pm
Bugzilla/Hook.pm
extensions/Example/Extension.pm
template/en/default/global/code-error.html.tmpl

index 395cc0dc9d7d3c057683a17d97bc31dbcef07903..178f6f90cfb1351802bfa4c58771520e0704d074 100644 (file)
@@ -92,57 +92,62 @@ 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.
+    require Bugzilla::Hook;
+    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() };
-            require Bugzilla::Hook;
-            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;
index 274a50618c088ed56c688a7145f72c64cb5c994b..da17946c0126b919dd8592543437685170daea67 100644 (file)
@@ -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
index f55e60637ca34ca27c6cafb50aa70b0ca14ba580..885a8e8ff779e45f236667d94a6cbef6d9ce96c9 100644 (file)
@@ -355,6 +355,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) = @_;
     
index f100df994e5176afba3fa24ac4ca9e2243cdc18e..f09415cc230e4c5827673a95b9014861703abfd4 100644 (file)
 
 <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>