Merge pull request #12843 from annando/fetchraw-attachments

Catch all errors thrown by "fetchRaw"
This commit is contained in:
Philipp 2023-02-27 08:24:05 +01:00 committed by GitHub
commit a40ecb3902
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 104 additions and 60 deletions

View File

@ -73,7 +73,12 @@ class Avatar
return $fields; return $fields;
} }
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]); try {
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
} catch (\Exception $exception) {
Logger::notice('Avatar is invalid', ['avatar' => $avatar, 'exception' => $exception]);
return $fields;
}
$img_str = $fetchResult->getBody(); $img_str = $fetchResult->getBody();
if (empty($img_str)) { if (empty($img_str)) {

View File

@ -168,7 +168,7 @@ class StorageManager
return $data['storage_config']; return $data['storage_config'];
} catch (InternalServerErrorException $exception) { } catch (InternalServerErrorException $exception) {
throw new StorageException(sprintf('Failed calling hook::storage_config for backend %s', $name), $exception); throw new StorageException(sprintf('Failed calling hook::storage_config for backend %s', $name), $exception->__toString());
} }
} }
} }
@ -208,7 +208,7 @@ class StorageManager
$this->backendInstances[$name] = new Type\SystemResource(); $this->backendInstances[$name] = new Type\SystemResource();
break; break;
case Type\ExternalResource::getName(): case Type\ExternalResource::getName():
$this->backendInstances[$name] = new Type\ExternalResource(); $this->backendInstances[$name] = new Type\ExternalResource($this->logger);
break; break;
default: default:
$data = [ $data = [
@ -223,7 +223,7 @@ class StorageManager
$this->backendInstances[$data['name'] ?? $name] = $data['storage']; $this->backendInstances[$data['name'] ?? $name] = $data['storage'];
} catch (InternalServerErrorException $exception) { } catch (InternalServerErrorException $exception) {
throw new StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception); throw new StorageException(sprintf('Failed calling hook::storage_instance for backend %s', $name), $exception->__toString());
} }
break; break;
} }

View File

@ -22,12 +22,12 @@
namespace Friendica\Core\Storage\Type; namespace Friendica\Core\Storage\Type;
use Exception; use Exception;
use Friendica\Core\Logger;
use Friendica\Core\Storage\Exception\ReferenceStorageException; use Friendica\Core\Storage\Exception\ReferenceStorageException;
use Friendica\Core\Storage\Capability\ICanReadFromStorage; use Friendica\Core\Storage\Capability\ICanReadFromStorage;
use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Util\HTTPSignature; use Friendica\Util\HTTPSignature;
use Psr\Log\LoggerInterface;
/** /**
* External resource storage class * External resource storage class
@ -39,6 +39,14 @@ class ExternalResource implements ICanReadFromStorage
{ {
const NAME = 'ExternalResource'; const NAME = 'ExternalResource';
/** @var LoggerInterface */
protected $logger;
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@ -57,10 +65,11 @@ class ExternalResource implements ICanReadFromStorage
try { try {
$fetchResult = HTTPSignature::fetchRaw($data->url, $data->uid, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]); $fetchResult = HTTPSignature::fetchRaw($data->url, $data->uid, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
} catch (Exception $exception) { } catch (Exception $exception) {
$this->logger->notice('URL is invalid', ['url' => $data->url, 'error' => $exception]);
throw new ReferenceStorageException(sprintf('External resource failed to get %s', $reference), $exception->getCode(), $exception); throw new ReferenceStorageException(sprintf('External resource failed to get %s', $reference), $exception->getCode(), $exception);
} }
if (!empty($fetchResult) && $fetchResult->isSuccess()) { if (!empty($fetchResult) && $fetchResult->isSuccess()) {
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => $data->uid, 'url' => $data->url]); $this->logger->debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => $data->uid, 'url' => $data->url]);
return $fetchResult->getBody(); return $fetchResult->getBody();
} else { } else {
if (empty($fetchResult)) { if (empty($fetchResult)) {

View File

@ -64,7 +64,7 @@ class Notification extends BaseFactory
if ($Notification->targetUriId) { if ($Notification->targetUriId) {
try { try {
$status = $this->mstdnStatusFactory->createFromUriId($Notification->targetUriId, $Notification->uid, $display_quotes); $status = $this->mstdnStatusFactory->createFromUriId($Notification->targetUriId, $Notification->uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
$status = null; $status = null;
} }
} else { } else {

View File

@ -269,8 +269,8 @@ class Status extends BaseFactory
if ($is_reshare) { if ($is_reshare) {
try { try {
$reshare = $this->createFromUriId($uriId, $uid, $display_quote, false, false)->toArray(); $reshare = $this->createFromUriId($uriId, $uid, $display_quote, false, false)->toArray();
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Reshare not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Reshare not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
$reshare = []; $reshare = [];
} }
} else { } else {
@ -280,8 +280,8 @@ class Status extends BaseFactory
if ($in_reply_status && ($item['gravity'] == Item::GRAVITY_COMMENT)) { if ($in_reply_status && ($item['gravity'] == Item::GRAVITY_COMMENT)) {
try { try {
$in_reply = $this->createFromUriId($item['thr-parent-id'], $uid, $display_quote, false, false)->toArray(); $in_reply = $this->createFromUriId($item['thr-parent-id'], $uid, $display_quote, false, false)->toArray();
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Reply post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Reply post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
$in_reply = []; $in_reply = [];
} }
} else { } else {
@ -315,8 +315,8 @@ class Status extends BaseFactory
if (!empty($quote_id)) { if (!empty($quote_id)) {
try { try {
$quote = $this->createFromUriId($quote_id, $uid, false, false, false)->toArray(); $quote = $this->createFromUriId($quote_id, $uid, false, false, false)->toArray();
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Quote not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Quote not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
$quote = []; $quote = [];
} }
} else { } else {

View File

@ -189,17 +189,22 @@ class APContact
if (empty($data)) { if (empty($data)) {
$local_owner = []; $local_owner = [];
$curlResult = HTTPSignature::fetchRaw($url); try {
$failed = empty($curlResult) || empty($curlResult->getBody()) || $curlResult = HTTPSignature::fetchRaw($url);
(!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410)); $failed = empty($curlResult) || empty($curlResult->getBody()) ||
(!$curlResult->isSuccess() && ($curlResult->getReturnCode() != 410));
if (!$failed) {
$data = json_decode($curlResult->getBody(), true);
$failed = empty($data) || !is_array($data);
}
if (!$failed) { if (!$failed && ($curlResult->getReturnCode() == 410)) {
$data = json_decode($curlResult->getBody(), true); $data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
$failed = empty($data) || !is_array($data); }
} } catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
if (!$failed && ($curlResult->getReturnCode() == 410)) { $failed = true;
$data = ['@context' => ActivityPub::CONTEXT, 'id' => $url, 'type' => 'Tombstone'];
} }
if ($failed) { if ($failed) {

View File

@ -2216,16 +2216,21 @@ class Contact
if (($contact['avatar'] != $avatar) || empty($contact['blurhash'])) { if (($contact['avatar'] != $avatar) || empty($contact['blurhash'])) {
$update_fields = ['avatar' => $avatar]; $update_fields = ['avatar' => $avatar];
if (!Network::isLocalLink($avatar)) { if (!Network::isLocalLink($avatar)) {
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]); try {
$fetchResult = HTTPSignature::fetchRaw($avatar, 0, [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE]]);
$img_str = $fetchResult->getBody(); $img_str = $fetchResult->getBody();
if (!empty($img_str)) { if (!empty($img_str)) {
$image = new Image($img_str, Images::getMimeTypeByData($img_str)); $image = new Image($img_str, Images::getMimeTypeByData($img_str));
if ($image->isValid()) { if ($image->isValid()) {
$update_fields['blurhash'] = $image->getBlurHash(); $update_fields['blurhash'] = $image->getBlurHash();
} else { } else {
return; return;
}
} }
} catch (\Exception $exception) {
Logger::notice('Error fetching avatar', ['avatar' => $avatar, 'exception' => $exception]);
return;
} }
} elseif (!empty($contact['blurhash'])) { } elseif (!empty($contact['blurhash'])) {
$update_fields['blurhash'] = null; $update_fields['blurhash'] = null;

View File

@ -125,8 +125,13 @@ class Link
{ {
$timeout = DI::config()->get('system', 'xrd_timeout'); $timeout = DI::config()->get('system', 'xrd_timeout');
$curlResult = HTTPSignature::fetchRaw($url, 0, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]); try {
if (empty($curlResult) || !$curlResult->isSuccess()) { $curlResult = HTTPSignature::fetchRaw($url, 0, [HttpClientOptions::TIMEOUT => $timeout, HttpClientOptions::ACCEPT_CONTENT => $accept]);
if (empty($curlResult) || !$curlResult->isSuccess()) {
return [];
}
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
return []; return [];
} }
$fields = ['mimetype' => $curlResult->getHeader('Content-Type')[0]]; $fields = ['mimetype' => $curlResult->getHeader('Content-Type')[0]];

View File

@ -120,8 +120,8 @@ class Statuses extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -77,8 +77,8 @@ class Bookmarks extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -79,8 +79,8 @@ class Favourited extends BaseApi
self::setBoundaries($item['thr-parent-id']); self::setBoundaries($item['thr-parent-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['thr-parent-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['thr-parent-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['thr-parent-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -117,7 +117,7 @@ class Accounts extends BaseApi
self::setBoundaries($member['contact-id']); self::setBoundaries($member['contact-id']);
try { try {
$accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid); $accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid);
} catch (\Throwable $th) { } catch (\Exception $exception) {
} }
} }
DBA::close($members); DBA::close($members);

View File

@ -183,8 +183,8 @@ class Search extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -99,8 +99,8 @@ class Home extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -104,8 +104,8 @@ class ListTimeline extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -99,8 +99,8 @@ class PublicTimeline extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -120,8 +120,8 @@ class Tag extends BaseApi
self::setBoundaries($item['uri-id']); self::setBoundaries($item['uri-id']);
try { try {
$statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes); $statuses[] = DI::mstdnStatus()->createFromUriId($item['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($items); DBA::close($items);

View File

@ -57,8 +57,8 @@ class Statuses extends BaseApi
while ($status = Post::fetch($statuses)) { while ($status = Post::fetch($statuses)) {
try { try {
$trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid, $display_quotes); $trending[] = DI::mstdnStatus()->createFromUriId($status['uri-id'], $uid, $display_quotes);
} catch (\Throwable $th) { } catch (\Exception $exception) {
Logger::info('Post not fetchable', ['uri-id' => $status['uri-id'], 'uid' => $uid, 'error' => $th]); Logger::info('Post not fetchable', ['uri-id' => $status['uri-id'], 'uid' => $uid, 'exception' => $exception]);
} }
} }
DBA::close($statuses); DBA::close($statuses);

View File

@ -83,13 +83,18 @@ class Proxy extends BaseModule
$request['url'] = str_replace(' ', '+', $request['url']); $request['url'] = str_replace(' ', '+', $request['url']);
// Fetch the content with the local user // Fetch the content with the local user
$fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]); try {
$img_str = $fetchResult->getBody(); $fetchResult = HTTPSignature::fetchRaw($request['url'], DI::userSession()->getLocalUserId(), [HttpClientOptions::ACCEPT_CONTENT => [HttpClientAccept::IMAGE], 'timeout' => 10]);
$img_str = $fetchResult->getBody();
if (!$fetchResult->isSuccess() || empty($img_str)) { if (!$fetchResult->isSuccess() || empty($img_str)) {
Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]); Logger::notice('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]);
self::responseError();
// stop.
}
} catch (\Exception $exception) {
Logger::notice('Error fetching image', ['image' => $request['url'], 'exception' => $exception]);
self::responseError(); self::responseError();
// stop.
} }
Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => DI::userSession()->getLocalUserId(), 'image' => $request['url']]); Logger::debug('Got picture', ['Content-Type' => $fetchResult->getHeader('Content-Type'), 'uid' => DI::userSession()->getLocalUserId(), 'image' => $request['url']]);

View File

@ -718,7 +718,7 @@ class Image
if ($image->isImagick()) { if ($image->isImagick()) {
try { try {
$colors = $image->image->getImagePixelColor($x, $y)->getColor(); $colors = $image->image->getImagePixelColor($x, $y)->getColor();
} catch (\Throwable $th) { } catch (\Exception $exception) {
return ''; return '';
} }
$row[] = [$colors['r'], $colors['g'], $colors['b']]; $row[] = [$colors['r'], $colors['g'], $colors['b']];

View File

@ -570,7 +570,12 @@ class Processor
*/ */
public static function isActivityGone(string $url): bool public static function isActivityGone(string $url): bool
{ {
$curlResult = HTTPSignature::fetchRaw($url, 0); try {
$curlResult = HTTPSignature::fetchRaw($url, 0);
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $url, 'exception' => $exception]);
return true;
}
if (Network::isUrlBlocked($url)) { if (Network::isUrlBlocked($url)) {
return true; return true;

View File

@ -422,7 +422,12 @@ class HTTPSignature
*/ */
public static function fetch(string $request, int $uid): array public static function fetch(string $request, int $uid): array
{ {
$curlResult = self::fetchRaw($request, $uid); try {
$curlResult = self::fetchRaw($request, $uid);
} catch (\Exception $exception) {
Logger::notice('Error fetching url', ['url' => $request, 'exception' => $exception]);
return [];
}
if (empty($curlResult)) { if (empty($curlResult)) {
return []; return [];