diff --git a/app/Exceptions/HttpFetchException.php b/app/Exceptions/HttpFetchException.php index 4ad45d92a..c445896c0 100644 --- a/app/Exceptions/HttpFetchException.php +++ b/app/Exceptions/HttpFetchException.php @@ -2,8 +2,22 @@ namespace BookStack\Exceptions; -use Exception; - -class HttpFetchException extends Exception +class HttpFetchException extends PrettyException { + /** + * 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; + } } diff --git a/app/Uploads/HttpFetcher.php b/app/Uploads/HttpFetcher.php index 4198bb2a3..fcb4147e9 100644 --- a/app/Uploads/HttpFetcher.php +++ b/app/Uploads/HttpFetcher.php @@ -29,7 +29,8 @@ class HttpFetcher curl_close($ch); if ($err) { - throw new HttpFetchException($err); + $errno = curl_errno($ch); + throw new HttpFetchException($err, $errno); } return $data; diff --git a/app/Uploads/UserAvatars.php b/app/Uploads/UserAvatars.php index 89e88bd19..1cad3465c 100644 --- a/app/Uploads/UserAvatars.php +++ b/app/Uploads/UserAvatars.php @@ -33,8 +33,8 @@ class UserAvatars $avatar = $this->saveAvatarImage($user); $user->avatar()->associate($avatar); $user->save(); - } catch (Exception $e) { - Log::error('Failed to save user avatar image'); + } catch (HttpFetchException $e) { + Log::error('Failed to save user avatar image', ['exception' => $e]); } } @@ -48,8 +48,8 @@ class UserAvatars $avatar = $this->createAvatarImageFromData($user, $imageData, $extension); $user->avatar()->associate($avatar); $user->save(); - } catch (Exception $e) { - Log::error('Failed to save user avatar image'); + } catch (HttpFetchException $e) { + 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. * - * @throws Exception + * @throws HttpFetchException */ protected function getAvatarImageData(string $url): string { try { $imageData = $this->http->fetch($url); } 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; diff --git a/tests/Uploads/AvatarTest.php b/tests/Uploads/AvatarTest.php index 2217cd2ba..363c1fa95 100644 --- a/tests/Uploads/AvatarTest.php +++ b/tests/Uploads/AvatarTest.php @@ -4,6 +4,7 @@ namespace Tests\Uploads; use BookStack\Exceptions\HttpFetchException; use BookStack\Uploads\HttpFetcher; +use BookStack\Uploads\UserAvatars; use BookStack\Users\Models\User; use Tests\TestCase; @@ -110,4 +111,28 @@ class AvatarTest extends TestCase $this->createUserRequest($user); $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); + } }