1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

When a page throws an exception and response construction throws another exception, throw an aggregate exception

Summary:
Depends on D20719. Currently, if a page throws an exception (like a policy exception) and rendering that exception into a response (like a policy dialog) throws another exception (for example, while constructing breadcrumbs), we only show the orginal exception.

This is usually the more useful exception, but sometimes we actually care about the other exception.

Instead of guessing which one is more likely to be useful, throw them both as an "AggregateException" and let the high-level handler flatten it for display.

Test Plan: {F6749312}

Differential Revision: https://secure.phabricator.com/D20720
This commit is contained in:
epriestley 2019-08-16 14:43:42 -07:00
parent 201634848e
commit 26ec924732
2 changed files with 53 additions and 9 deletions

View file

@ -312,11 +312,17 @@ final class AphrontApplicationConfiguration
if ($response_exception) {
// If we encountered an exception while building a normal response, then
// encountered another exception while building a response for the first
// exception, just throw the original exception. It is more likely to be
// useful and point at a root cause than the second exception we ran into
// while telling the user about it.
// exception, throw an aggregate exception that will be unpacked by the
// higher-level handler. This is above our pay grade.
if ($original_exception) {
throw $original_exception;
throw new PhutilAggregateException(
pht(
'Encountered a processing exception, then another exception when '.
'trying to build a response for the first exception.'),
array(
$response_exception,
$original_exception,
));
}
// If we built a response successfully and then ran into an exception

View file

@ -61,9 +61,39 @@ final class AphrontUnhandledExceptionResponse
return 'unhandled-exception';
}
protected function getResponseBody() {
$ex = $this->exception;
private function getExceptionList() {
return $this->expandException($this->exception);
}
private function expandException($root) {
if ($root instanceof PhutilAggregateException) {
$list = array();
$list[] = $root;
foreach ($root->getExceptions() as $ex) {
foreach ($this->expandException($ex) as $child) {
$list[] = $child;
}
}
return $list;
}
return array($root);
}
protected function getResponseBody() {
$body = array();
foreach ($this->getExceptionList() as $ex) {
$body[] = $this->newHTMLMessage($ex);
}
return $body;
}
private function newHTMLMessage($ex) {
if ($ex instanceof AphrontMalformedRequestException) {
$title = $ex->getTitle();
} else {
@ -122,12 +152,20 @@ final class AphrontUnhandledExceptionResponse
}
protected function buildPlainTextResponseString() {
$ex = $this->exception;
$messages = array();
foreach ($this->getExceptionList() as $exception) {
$messages[] = $this->newPlainTextMessage($exception);
}
return implode("\n\n", $messages);
}
private function newPlainTextMessage($exception) {
return pht(
'%s: %s',
get_class($ex),
$ex->getMessage());
get_class($exception),
$exception->getMessage());
}
}