Modify HttpFetchException handle to log exception

Within the flow of HttpFetchException, the actual exception from curl is preserved and logged. Make HttpFetchException a pretty exception for when it is shown to users.
This commit is contained in:
Thomas Kuschan 2023-06-14 14:09:52 +02:00
parent ec775aec02
commit c35080d6ce
4 changed files with 50 additions and 10 deletions

View File

@ -2,8 +2,22 @@
namespace BookStack\Exceptions; namespace BookStack\Exceptions;
use Exception; class HttpFetchException extends PrettyException
class HttpFetchException extends Exception
{ {
/**
* Construct exception within BookStack\Uploads\HttpFetcher.
*/
public function __construct(string $message = '', int $code = 0, ?\Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
if ($previous) {
$this->setDetails($previous->getMessage());
}
}
public function getStatusCode(): int
{
return 500;
}
} }

View File

@ -29,7 +29,8 @@ class HttpFetcher
curl_close($ch); curl_close($ch);
if ($err) { if ($err) {
throw new HttpFetchException($err); $errno = curl_errno($ch);
throw new HttpFetchException($err, $errno);
} }
return $data; return $data;

View File

@ -33,8 +33,8 @@ class UserAvatars
$avatar = $this->saveAvatarImage($user); $avatar = $this->saveAvatarImage($user);
$user->avatar()->associate($avatar); $user->avatar()->associate($avatar);
$user->save(); $user->save();
} catch (Exception $e) { } catch (HttpFetchException $e) {
Log::error('Failed to save user avatar image'); Log::error('Failed to save user avatar image', ['exception' => $e]);
} }
} }
@ -48,8 +48,8 @@ class UserAvatars
$avatar = $this->createAvatarImageFromData($user, $imageData, $extension); $avatar = $this->createAvatarImageFromData($user, $imageData, $extension);
$user->avatar()->associate($avatar); $user->avatar()->associate($avatar);
$user->save(); $user->save();
} catch (Exception $e) { } catch (HttpFetchException $e) {
Log::error('Failed to save user avatar image'); Log::error('Failed to save user avatar image', ['exception' => $e]);
} }
} }
@ -107,14 +107,14 @@ class UserAvatars
/** /**
* Gets an image from url and returns it as a string of image data. * Gets an image from url and returns it as a string of image data.
* *
* @throws Exception * @throws HttpFetchException
*/ */
protected function getAvatarImageData(string $url): string protected function getAvatarImageData(string $url): string
{ {
try { try {
$imageData = $this->http->fetch($url); $imageData = $this->http->fetch($url);
} catch (HttpFetchException $exception) { } catch (HttpFetchException $exception) {
throw new Exception(trans('errors.cannot_get_image_from_url', ['url' => $url])); throw new HttpFetchException(trans('errors.cannot_get_image_from_url', ['url' => $url]), $exception->getCode(), $exception);
} }
return $imageData; return $imageData;

View File

@ -4,6 +4,7 @@ namespace Tests\Uploads;
use BookStack\Exceptions\HttpFetchException; use BookStack\Exceptions\HttpFetchException;
use BookStack\Uploads\HttpFetcher; use BookStack\Uploads\HttpFetcher;
use BookStack\Uploads\UserAvatars;
use BookStack\Users\Models\User; use BookStack\Users\Models\User;
use Tests\TestCase; use Tests\TestCase;
@ -110,4 +111,28 @@ class AvatarTest extends TestCase
$this->createUserRequest($user); $this->createUserRequest($user);
$this->assertTrue($logger->hasError('Failed to save user avatar image')); $this->assertTrue($logger->hasError('Failed to save user avatar image'));
} }
public function test_exception_message_on_failed_fetch()
{
// set wrong url
config()->set([
'services.disable_services' => false,
'services.avatar_url' => 'http_malformed_url/${email}/${hash}/${size}',
]);
$user = User::factory()->make();
$avatar = app()->make(UserAvatars::class);
$url = 'http_malformed_url/' . urlencode(strtolower($user->email)) . '/' . md5(strtolower($user->email)) . '/500';
$logger = $this->withTestLogger();
$avatar->fetchAndAssignToUser($user);
$this->assertTrue($logger->hasError('Failed to save user avatar image'));
$exception = $logger->getRecords()[0]['context']['exception'];
$this->assertEquals(new HttpFetchException(
'Cannot get image from ' . $url,
6,
(new HttpFetchException('Could not resolve host: http_malformed_url', 6))
), $exception);
}
} }