From bfc1c157f1e4d2e84437e6f149bdb3e8b6290b8a Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 26 Dec 2022 13:08:41 +0100 Subject: [PATCH 1/5] Adapt UserSession - Move from App methods to UserSession methods - Deprecate corresponding App methods --- src/App.php | 52 +++++-------------- .../Capability/IHandleUserSessions.php | 14 +++++ src/Core/Session/Model/UserSession.php | 17 ++++++ src/Model/User.php | 16 ++++++ src/Security/Authentication.php | 3 -- .../Api/Twitter/DirectMessages/NewDMTest.php | 6 +-- 6 files changed, 62 insertions(+), 46 deletions(-) diff --git a/src/App.php b/src/App.php index eb0d1cc217..b41215380f 100644 --- a/src/App.php +++ b/src/App.php @@ -29,7 +29,6 @@ use Friendica\Core\Config\Factory\Config; use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Database\Definition\DbaDefinition; use Friendica\Database\Definition\ViewDefinition; -use Friendica\Model\User; use Friendica\Module\Maintenance; use Friendica\Security\Authentication; use Friendica\Core\Config\ValueObject\Cache; @@ -73,8 +72,6 @@ class App 'videoheight' => 350, ]; - private $user_id = 0; - private $nickname = ''; private $timezone = ''; private $profile_owner = 0; private $contact_id = 0; @@ -136,64 +133,39 @@ class App private $session; /** - * Set the user ID - * - * @param int $user_id - * @return void + * @deprecated 2022.03 + * @see IHandleUserSessions::isAuthenticated() */ - public function setLoggedInUserId(int $user_id) - { - $this->user_id = $user_id; - } - - /** - * Set the nickname - * - * @param int $user_id - * @return void - */ - public function setLoggedInUserNickname(string $nickname) - { - $this->nickname = $nickname; - } - public function isLoggedIn(): bool { - return $this->session->getLocalUserId() && $this->user_id && ($this->user_id == $this->session->getLocalUserId()); + return $this->session->isAuthenticated(); } /** - * Check if current user has admin role. - * - * @return bool true if user is an admin - * @throws Exception + * @deprecated 2022.03 + * @see IHandleUserSessions::isSiteAdmin() */ public function isSiteAdmin(): bool { - return - $this->session->getLocalUserId() - && $this->database->exists('user', [ - 'uid' => $this->getLoggedInUserId(), - 'email' => User::getAdminEmailList() - ]); + return $this->session->isSiteAdmin(); } /** - * Fetch the user id - * @return int User id + * @deprecated 2022.03 + * @see IHandleUserSessions::getLocalUserId() */ public function getLoggedInUserId(): int { - return $this->user_id; + return $this->session->getLocalUserId(); } /** - * Fetch the user nick name - * @return string User's nickname + * @deprecated 2022.03 + * @see IHandleUserSessions::getLocalUserNickname() */ public function getLoggedInUserNickname(): string { - return $this->nickname; + return $this->session->getLocalUserNickname(); } /** diff --git a/src/Core/Session/Capability/IHandleUserSessions.php b/src/Core/Session/Capability/IHandleUserSessions.php index e65749c8df..7a6ca64ba1 100644 --- a/src/Core/Session/Capability/IHandleUserSessions.php +++ b/src/Core/Session/Capability/IHandleUserSessions.php @@ -33,6 +33,13 @@ interface IHandleUserSessions extends IHandleSessions */ public function getLocalUserId(); + /** + * Returns the user nickname of locally logged-in user. + * + * @return string|false User's nickname or false + */ + public function getLocalUserNickname(); + /** * Returns the public contact id of logged-in user or false. * @@ -79,6 +86,13 @@ interface IHandleUserSessions extends IHandleSessions */ public function isAuthenticated(): bool; + /** + * Check if current user has admin role. + * + * @return bool true if user is an admin + */ + public function isSiteAdmin(): bool; + /** * Returns User ID of the managed user in case it's a different identity * diff --git a/src/Core/Session/Model/UserSession.php b/src/Core/Session/Model/UserSession.php index 959ca1af2d..6cd689e9c7 100644 --- a/src/Core/Session/Model/UserSession.php +++ b/src/Core/Session/Model/UserSession.php @@ -24,6 +24,7 @@ namespace Friendica\Core\Session\Model; use Friendica\Core\Session\Capability\IHandleSessions; use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Model\Contact; +use Friendica\Model\User; /** * This class handles user sessions, which is directly extended from regular session @@ -50,6 +51,16 @@ class UserSession implements IHandleUserSessions return false; } + /** {@inheritDoc} */ + public function getLocalUserNickname() + { + if ($this->isAuthenticated()) { + return $this->session->get('nickname'); + } + + return false; + } + /** {@inheritDoc} */ public function getPublicContactId() { @@ -122,6 +133,12 @@ class UserSession implements IHandleUserSessions return $this->session->get('authenticated', false); } + /** {@inheritDoc} */ + public function isSiteAdmin(): bool + { + return User::isSiteAdmin($this->getLocalUserId()); + } + /** {@inheritDoc} */ public function setVisitorsContacts() { diff --git a/src/Model/User.php b/src/Model/User.php index 132e4f11a9..916844251e 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -830,6 +830,22 @@ class User return DBA::update('user', $fields, ['uid' => $uid]); } + /** + * Returns if the given uid is valid and in the admin list + * + * @param int $uid + * + * @return bool + * @throws Exception + */ + public static function isSiteAdmin(int $uid): bool + { + return DBA::exists('user', [ + 'uid' => $uid, + 'email' => self::getAdminEmailList() + ]); + } + /** * Checks if a nickname is in the list of the forbidden nicknames * diff --git a/src/Security/Authentication.php b/src/Security/Authentication.php index 5dcc399403..c6a8403672 100644 --- a/src/Security/Authentication.php +++ b/src/Security/Authentication.php @@ -392,9 +392,6 @@ class Authentication } } - $a->setLoggedInUserId($user_record['uid']); - $a->setLoggedInUserNickname($user_record['nickname']); - if ($login_initial) { Hook::callAll('logged_in', $user_record); } diff --git a/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php b/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php index b2bcfb37fa..cab3c22026 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php @@ -88,7 +88,7 @@ class NewDMTest extends ApiTest */ public function testApiDirectMessagesNewWithScreenName() { - DI::app()->setLoggedInUserNickname('selfcontact'); + DI::session()->set('nickname', 'selfcontact'); $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); @@ -112,7 +112,7 @@ class NewDMTest extends ApiTest */ public function testApiDirectMessagesNewWithTitle() { - DI::app()->setLoggedInUserNickname('selfcontact'); + DI::session()->set('nickname', 'selfcontact'); $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); @@ -138,7 +138,7 @@ class NewDMTest extends ApiTest */ public function testApiDirectMessagesNewWithRss() { - DI::app()->setLoggedInUserNickname('selfcontact'); + DI::session()->set('nickname', 'selfcontact'); $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); From 10864e50c722ba73afd013e41d90aaa497ea6300 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 25 Dec 2022 16:48:09 +0100 Subject: [PATCH 2/5] Adapt Logger\Introspection - Create an interface - Add it as constructor parameter --- .../Capabilities/IHaveCallIntrospections.php | 52 +++++++++++++++++++ src/Core/Logger/Factory/Logger.php | 26 +++------- src/Core/Logger/Util/Introspection.php | 6 ++- static/dependencies.config.php | 6 +++ 4 files changed, 68 insertions(+), 22 deletions(-) create mode 100644 src/Core/Logger/Capabilities/IHaveCallIntrospections.php diff --git a/src/Core/Logger/Capabilities/IHaveCallIntrospections.php b/src/Core/Logger/Capabilities/IHaveCallIntrospections.php new file mode 100644 index 0000000000..e9f27ee1ad --- /dev/null +++ b/src/Core/Logger/Capabilities/IHaveCallIntrospections.php @@ -0,0 +1,52 @@ +. + * + */ + +namespace Friendica\Core\Logger\Capabilities; +use Friendica\Core\Logger\Factory\Logger; +use Friendica\Util\Profiler; + +interface IHaveCallIntrospections +{ + /** + * A list of classes, which shouldn't get logged + * + * @var string[] + */ + public const IGNORE_CLASS_LIST = [ + Logger::class, + Profiler::class, + 'Friendica\\Core\\Logger\\Type', + ]; + + /** + * Adds new classes to get skipped + * + * @param array $classNames + */ + public function addClasses(array $classNames): void; + + /** + * Returns the introspection record of the current call + * + * @return array + */ + public function getRecord(): array; +} diff --git a/src/Core/Logger/Factory/Logger.php b/src/Core/Logger/Factory/Logger.php index 4df7d8ecaf..30e949a681 100644 --- a/src/Core/Logger/Factory/Logger.php +++ b/src/Core/Logger/Factory/Logger.php @@ -23,11 +23,11 @@ namespace Friendica\Core\Logger\Factory; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core; +use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Database\Database; use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Util\FileSystem; -use Friendica\Core\Logger\Util\Introspection; use Friendica\Core\Logger\Type\ProfilerLogger; use Friendica\Core\Logger\Type\StreamLogger; use Friendica\Core\Logger\Type\SyslogLogger; @@ -43,17 +43,6 @@ class Logger { const DEV_CHANNEL = 'dev'; - /** - * A list of classes, which shouldn't get logged - * - * @var string[] - */ - private static $ignoreClassList = [ - Core\Logger::class, - Profiler::class, - 'Friendica\\Core\\Logger\\Type', - ]; - /** @var string The log-channel (app, worker, ...) */ private $channel; @@ -79,7 +68,7 @@ class Logger * * @return LoggerInterface The PSR-3 compliant logger instance */ - public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, ?string $minLevel = null): LoggerInterface + public function create(Database $database, IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection, ?string $minLevel = null): LoggerInterface { if (empty($config->get('system', 'debugging', false))) { $logger = new NullLogger(); @@ -87,7 +76,6 @@ class Logger return $logger; } - $introspection = new Introspection(self::$ignoreClassList); $minLevel = $minLevel ?? $config->get('system', 'loglevel'); $loglevel = self::mapLegacyConfigDebugLevel((string)$minLevel); @@ -99,7 +87,7 @@ class Logger $logger = new SyslogLogger($this->channel, $introspection, $loglevel, $config->get('system', 'syslog_flags', SyslogLogger::DEFAULT_FLAGS), $config->get('system', 'syslog_facility', SyslogLogger::DEFAULT_FACILITY)); } catch (LogLevelException $exception) { // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE); + $logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); } catch (\Throwable $e) { // No logger ... @@ -134,7 +122,7 @@ class Logger $logger = new StreamLogger($this->channel, $stream, $introspection, $fileSystem, $loglevel); } catch (LogLevelException $exception) { // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE); + $logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); } catch (\Throwable $t) { // No logger ... @@ -145,7 +133,7 @@ class Logger $logger = new SyslogLogger($this->channel, $introspection, $loglevel); } catch (LogLevelException $exception) { // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create($database, $config, $profiler, $fileSystem, LogLevel::NOTICE); + $logger = $this->create($database, $config, $profiler, $fileSystem, $introspection, LogLevel::NOTICE); $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); } catch (\Throwable $e) { // No logger ... @@ -182,7 +170,7 @@ class Logger * @return LoggerInterface The PSR-3 compliant logger instance * @throws \Exception */ - public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem) + public static function createDev(IManageConfigValues $config, Profiler $profiler, FileSystem $fileSystem, IHaveCallIntrospections $introspection) { $debugging = $config->get('system', 'debugging'); $stream = $config->get('system', 'dlogfile'); @@ -193,8 +181,6 @@ class Logger return new NullLogger(); } - $introspection = new Introspection(self::$ignoreClassList); - $name = $config->get('system', 'logger_config', 'stream'); switch ($name) { diff --git a/src/Core/Logger/Util/Introspection.php b/src/Core/Logger/Util/Introspection.php index 83d1b6faf5..444af2409e 100644 --- a/src/Core/Logger/Util/Introspection.php +++ b/src/Core/Logger/Util/Introspection.php @@ -21,10 +21,12 @@ namespace Friendica\Core\Logger\Util; +use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; + /** * Get Introspection information about the current call */ -class Introspection +class Introspection implements IHaveCallIntrospections { /** @var int */ private $skipStackFramesCount; @@ -52,7 +54,7 @@ class Introspection * * @param array $classNames */ - public function addClasses(array $classNames) + public function addClasses(array $classNames): void { $this->skipClassesPartials = array_merge($this->skipClassesPartials, $classNames); } diff --git a/static/dependencies.config.php b/static/dependencies.config.php index a7de89d614..fd242c3417 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -176,6 +176,12 @@ return [ ['createDev', [], Dice::CHAIN_CALL], ] ], + \Friendica\Core\Logger\Capabilities\IHaveCallIntrospections::class => [ + 'instanceOf' => \Friendica\Core\Logger\Util\Introspection::class, + 'constructParams' => [ + \Friendica\Core\Logger\Util\Introspection::IGNORE_CLASS_LIST, + ], + ], Cache\Capability\ICanCache::class => [ 'instanceOf' => Cache\Factory\Cache::class, 'call' => [ From 5584e7a4e5725944020ba6972c724b2371e2bdd6 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 25 Dec 2022 19:19:06 +0100 Subject: [PATCH 3/5] Use X-REQUEST-ID for Logging --- src/App/Request.php | 20 ++++++++++++++++++++ src/Core/Logger/Util/Introspection.php | 14 ++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/App/Request.php b/src/App/Request.php index 71b6a9ea3f..1af1206d1f 100644 --- a/src/App/Request.php +++ b/src/App/Request.php @@ -22,6 +22,7 @@ namespace Friendica\App; use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\System; /** * Container for the whole request @@ -38,9 +39,17 @@ class Request * @var string */ const DEFAULT_FORWARD_FOR_HEADER = 'HTTP_X_FORWARDED_FOR'; + /** + * The default Request-ID header to retrieve the current transaction ID from the HTTP header (if set) + * + * @var string + */ + const DEFAULT_REQUEST_ID_HEADER = 'HTTP_X_REQUEST_ID'; /** @var string The remote IP address of the current request */ protected $remoteAddress; + /** @var string The request-id of the current request */ + protected $requestId; /** * @return string The remote IP address of the current request @@ -52,9 +61,20 @@ class Request return $this->remoteAddress; } + /** + * @return string The request ID of the current request + * + * Do always use this instead of $_SERVER['X_REQUEST_ID'] + */ + public function getRequestId(): string + { + return $this->requestId; + } + public function __construct(IManageConfigValues $config, array $server = []) { $this->remoteAddress = $this->determineRemoteAddress($config, $server); + $this->requestId = $server[static::DEFAULT_REQUEST_ID_HEADER] ?? System::createGUID(8); } /** diff --git a/src/Core/Logger/Util/Introspection.php b/src/Core/Logger/Util/Introspection.php index 444af2409e..987a4e3cba 100644 --- a/src/Core/Logger/Util/Introspection.php +++ b/src/Core/Logger/Util/Introspection.php @@ -21,6 +21,7 @@ namespace Friendica\Core\Logger\Util; +use Friendica\App\Request; use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; /** @@ -28,6 +29,9 @@ use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; */ class Introspection implements IHaveCallIntrospections { + /** @var string */ + private $requestId; + /** @var int */ private $skipStackFramesCount; @@ -43,8 +47,9 @@ class Introspection implements IHaveCallIntrospections * @param string[] $skipClassesPartials An array of classes to skip during logging * @param int $skipStackFramesCount If the logger should use information from other hierarchy levels of the call */ - public function __construct(array $skipClassesPartials = [], int $skipStackFramesCount = 0) + public function __construct(Request $request, array $skipClassesPartials = [], int $skipStackFramesCount = 0) { + $this->requestId = $request->getRequestId(); $this->skipClassesPartials = $skipClassesPartials; $this->skipStackFramesCount = $skipStackFramesCount; } @@ -77,9 +82,10 @@ class Introspection implements IHaveCallIntrospections $i += $this->skipStackFramesCount; return [ - 'file' => isset($trace[$i - 1]['file']) ? basename($trace[$i - 1]['file']) : null, - 'line' => $trace[$i - 1]['line'] ?? null, - 'function' => $trace[$i]['function'] ?? null, + 'file' => isset($trace[$i - 1]['file']) ? basename($trace[$i - 1]['file']) : null, + 'line' => $trace[$i - 1]['line'] ?? null, + 'function' => $trace[$i]['function'] ?? null, + 'request-id' => $this->requestId, ]; } From 4f1bb0d274f3a28ca6513184bc21a98b8c32fe56 Mon Sep 17 00:00:00 2001 From: Philipp Date: Mon, 26 Dec 2022 21:17:32 +0100 Subject: [PATCH 4/5] Use X-REQUEST-ID for Error pages --- index.php | 1 + src/App.php | 9 +-- src/BaseModule.php | 4 +- src/Capabilities/ICanHandleRequests.php | 6 +- src/Module/Api/Mastodon/Apps.php | 5 +- src/Module/BaseApi.php | 5 +- src/Module/HTTPException/MethodNotAllowed.php | 3 +- src/Module/HTTPException/PageNotFound.php | 8 +-- src/Module/OAuth/Acknowledge.php | 5 +- src/Module/OAuth/Revoke.php | 5 +- src/Module/OAuth/Token.php | 5 +- src/Module/Special/HTTPException.php | 70 ++++++++++++++----- static/dependencies.config.php | 7 +- tests/src/Module/Api/ApiTest.php | 7 ++ .../Friendica/DirectMessages/SearchTest.php | 6 +- .../Module/Api/Friendica/NotificationTest.php | 4 +- .../Module/Api/Friendica/Photo/DeleteTest.php | 8 +-- .../Api/Friendica/Photoalbum/DeleteTest.php | 6 +- .../Api/Friendica/Photoalbum/UpdateTest.php | 8 +-- .../Api/GnuSocial/GnuSocial/ConfigTest.php | 2 +- .../Api/GnuSocial/GnuSocial/VersionTest.php | 2 +- .../Module/Api/GnuSocial/Help/TestTest.php | 4 +- .../Accounts/VerifyCredentialsTest.php | 2 +- .../Twitter/Account/RateLimitStatusTest.php | 4 +- .../Api/Twitter/Account/UpdateProfileTest.php | 2 +- .../Module/Api/Twitter/Blocks/ListsTest.php | 2 +- .../Api/Twitter/DirectMessages/AllTest.php | 2 +- .../DirectMessages/ConversationTest.php | 2 +- .../Twitter/DirectMessages/DestroyTest.php | 10 +-- .../Api/Twitter/DirectMessages/InboxTest.php | 2 +- .../Api/Twitter/DirectMessages/NewDMTest.php | 10 +-- .../Api/Twitter/DirectMessages/SentTest.php | 4 +- .../Api/Twitter/Favorites/CreateTest.php | 6 +- .../Api/Twitter/Favorites/DestroyTest.php | 4 +- .../src/Module/Api/Twitter/FavoritesTest.php | 4 +- .../Api/Twitter/Followers/ListsTest.php | 2 +- .../Module/Api/Twitter/Friends/ListsTest.php | 2 +- .../Api/Twitter/Friendships/IncomingTest.php | 2 +- .../Module/Api/Twitter/Lists/StatusesTest.php | 6 +- .../Module/Api/Twitter/Media/UploadTest.php | 8 +-- .../Module/Api/Twitter/SavedSearchesTest.php | 2 +- .../Api/Twitter/Statuses/DestroyTest.php | 4 +- .../Api/Twitter/Statuses/MentionsTest.php | 6 +- .../Statuses/NetworkPublicTimelineTest.php | 6 +- .../Api/Twitter/Statuses/RetweetTest.php | 6 +- .../Module/Api/Twitter/Statuses/ShowTest.php | 6 +- .../Api/Twitter/Statuses/UpdateTest.php | 4 +- .../Api/Twitter/Statuses/UserTimelineTest.php | 6 +- .../Module/Api/Twitter/Users/LookupTest.php | 4 +- .../Module/Api/Twitter/Users/SearchTest.php | 6 +- .../src/Module/Api/Twitter/Users/ShowTest.php | 4 +- tests/src/Module/NodeInfoTest.php | 18 ++++- tests/src/Module/Special/OptionsTest.php | 16 ++++- view/templates/exception.tpl | 3 + view/templates/http_status.tpl | 3 + 55 files changed, 218 insertions(+), 130 deletions(-) diff --git a/index.php b/index.php index ba990532b8..c8d0037df0 100644 --- a/index.php +++ b/index.php @@ -45,6 +45,7 @@ $a->runFrontend( $dice->create(\Friendica\Core\PConfig\Capability\IManagePersonalConfigValues::class), $dice->create(\Friendica\Security\Authentication::class), $dice->create(\Friendica\App\Page::class), + $dice->create(Friendica\Module\Special\HTTPException::class), new \Friendica\Util\HTTPInputData($_SERVER), $start_time ); diff --git a/src/App.php b/src/App.php index b41215380f..b84c3b6294 100644 --- a/src/App.php +++ b/src/App.php @@ -573,13 +573,14 @@ class App * @param IManagePersonalConfigValues $pconfig * @param Authentication $auth The Authentication backend of the node * @param App\Page $page The Friendica page printing container + * @param ModuleHTTPException $httpException The possible HTTP Exception container * @param HTTPInputData $httpInput A library for processing PHP input streams * @param float $start_time The start time of the overall script execution * * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, HTTPInputData $httpInput, float $start_time) + public function runFrontend(App\Router $router, IManagePersonalConfigValues $pconfig, Authentication $auth, App\Page $page, ModuleHTTPException $httpException, HTTPInputData $httpInput, float $start_time) { $this->profiler->set($start_time, 'start'); $this->profiler->set(microtime(true), 'classinit'); @@ -713,9 +714,9 @@ class App $httpinput = $httpInput->process(); $input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST); - // Let the module run it's internal process (init, get, post, ...) + // Let the module run its internal process (init, get, post, ...) $timestamp = microtime(true); - $response = $module->run($input); + $response = $module->run($httpException, $input); $this->profiler->set(microtime(true) - $timestamp, 'content'); if ($response->getHeaderLine(ICanCreateResponses::X_HEADER) === ICanCreateResponses::TYPE_HTML) { $page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $this->session->getLocalUserId()); @@ -723,7 +724,7 @@ class App $page->exit($response); } } catch (HTTPException $e) { - (new ModuleHTTPException())->rawContent($e); + $httpException->rawContent($e); } $page->logRuntime($this->config, 'runFrontend'); } diff --git a/src/BaseModule.php b/src/BaseModule.php index 09107f0472..12efbce811 100644 --- a/src/BaseModule.php +++ b/src/BaseModule.php @@ -181,7 +181,7 @@ abstract class BaseModule implements ICanHandleRequests /** * {@inheritDoc} */ - public function run(array $request = []): ResponseInterface + public function run(ModuleHTTPException $httpException, array $request = []): ResponseInterface { // @see https://github.com/tootsuite/mastodon/blob/c3aef491d66aec743a3a53e934a494f653745b61/config/initializers/cors.rb if (substr($this->args->getQueryString(), 0, 12) == '.well-known/') { @@ -243,7 +243,7 @@ abstract class BaseModule implements ICanHandleRequests $this->response->addContent($arr['content']); $this->response->addContent($this->content($request)); } catch (HTTPException $e) { - $this->response->addContent((new ModuleHTTPException())->content($e)); + $this->response->addContent($httpException->content($e)); } finally { $this->profiler->set(microtime(true) - $timestamp, 'content'); } diff --git a/src/Capabilities/ICanHandleRequests.php b/src/Capabilities/ICanHandleRequests.php index 154eae69e5..c0f99eaa1b 100644 --- a/src/Capabilities/ICanHandleRequests.php +++ b/src/Capabilities/ICanHandleRequests.php @@ -21,6 +21,7 @@ namespace Friendica\Capabilities; +use Friendica\Module\Special\HTTPException as ModuleHTTPException; use Friendica\Network\HTTPException; use Psr\Http\Message\ResponseInterface; @@ -30,11 +31,12 @@ use Psr\Http\Message\ResponseInterface; interface ICanHandleRequests { /** - * @param array $request The $_REQUEST content (including content from the PHP input stream) + * @param ModuleHTTPException $httpException The special HTTPException Module in case of underlying errors + * @param array $request The $_REQUEST content (including content from the PHP input stream) * * @return ResponseInterface responding to the request handling * * @throws HTTPException\InternalServerErrorException */ - public function run(array $request = []): ResponseInterface; + public function run(ModuleHTTPException $httpException, array $request = []): ResponseInterface; } diff --git a/src/Module/Api/Mastodon/Apps.php b/src/Module/Api/Mastodon/Apps.php index f14ff68177..1c1ec80602 100644 --- a/src/Module/Api/Mastodon/Apps.php +++ b/src/Module/Api/Mastodon/Apps.php @@ -25,6 +25,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; +use Friendica\Module\Special\HTTPException; use Friendica\Util\Network; use Psr\Http\Message\ResponseInterface; @@ -33,9 +34,9 @@ use Psr\Http\Message\ResponseInterface; */ class Apps extends BaseApi { - public function run(array $request = [], bool $scopecheck = true): ResponseInterface + public function run(HTTPException $httpException, array $request = [], bool $scopecheck = true): ResponseInterface { - return parent::run($request, false); + return parent::run($httpException, $request, false); } /** diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index 1d5249ac85..82dda9de9f 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -33,6 +33,7 @@ use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\User; use Friendica\Module\Api\ApiResponse; +use Friendica\Module\Special\HTTPException as ModuleHTTPException; use Friendica\Network\HTTPException; use Friendica\Security\BasicAuth; use Friendica\Security\OAuth; @@ -80,7 +81,7 @@ class BaseApi extends BaseModule * * @throws HTTPException\ForbiddenException */ - public function run(array $request = [], bool $scopecheck = true): ResponseInterface + public function run(ModuleHTTPException $httpException, array $request = [], bool $scopecheck = true): ResponseInterface { if ($scopecheck) { switch ($this->args->getMethod()) { @@ -97,7 +98,7 @@ class BaseApi extends BaseModule } } - return parent::run($request); + return parent::run($httpException, $request); } /** diff --git a/src/Module/HTTPException/MethodNotAllowed.php b/src/Module/HTTPException/MethodNotAllowed.php index 7dc3737596..5728e0a376 100644 --- a/src/Module/HTTPException/MethodNotAllowed.php +++ b/src/Module/HTTPException/MethodNotAllowed.php @@ -22,13 +22,12 @@ namespace Friendica\Module\HTTPException; use Friendica\BaseModule; -use Friendica\DI; use Friendica\Network\HTTPException; class MethodNotAllowed extends BaseModule { protected function content(array $request = []): string { - throw new HTTPException\MethodNotAllowedException(DI::l10n()->t('Method Not Allowed.')); + throw new HTTPException\MethodNotAllowedException($this->t('Method Not Allowed.')); } } diff --git a/src/Module/HTTPException/PageNotFound.php b/src/Module/HTTPException/PageNotFound.php index ecebc7757a..2b6e546527 100644 --- a/src/Module/HTTPException/PageNotFound.php +++ b/src/Module/HTTPException/PageNotFound.php @@ -25,8 +25,8 @@ use Friendica\App; use Friendica\BaseModule; use Friendica\Core\L10n; use Friendica\Core\System; -use Friendica\DI; use Friendica\Module\Response; +use Friendica\Module\Special\HTTPException as ModuleHTTPException; use Friendica\Network\HTTPException; use Friendica\Util\Profiler; use Psr\Http\Message\ResponseInterface; @@ -46,10 +46,10 @@ class PageNotFound extends BaseModule protected function content(array $request = []): string { - throw new HTTPException\NotFoundException(DI::l10n()->t('Page not found.')); + throw new HTTPException\NotFoundException($this->t('Page not found.')); } - public function run(array $request = []): ResponseInterface + public function run(ModuleHTTPException $httpException, array $request = []): ResponseInterface { /* The URL provided does not resolve to a valid module. * @@ -77,6 +77,6 @@ class PageNotFound extends BaseModule 'query' => $this->server['QUERY_STRING'] ]); - return parent::run($request); // TODO: Change the autogenerated stub + return parent::run($httpException, $request); } } diff --git a/src/Module/OAuth/Acknowledge.php b/src/Module/OAuth/Acknowledge.php index fe947a63c0..e2a65a0e28 100644 --- a/src/Module/OAuth/Acknowledge.php +++ b/src/Module/OAuth/Acknowledge.php @@ -24,6 +24,7 @@ namespace Friendica\Module\OAuth; use Friendica\Core\Renderer; use Friendica\DI; use Friendica\Module\BaseApi; +use Friendica\Module\Special\HTTPException; use Psr\Http\Message\ResponseInterface; /** @@ -31,9 +32,9 @@ use Psr\Http\Message\ResponseInterface; */ class Acknowledge extends BaseApi { - public function run(array $request = [], bool $scopecheck = true): ResponseInterface + public function run(HTTPException $httpException, array $request = [], bool $scopecheck = true): ResponseInterface { - return parent::run($request, false); + return parent::run($httpException, $request, false); } protected function post(array $request = []) diff --git a/src/Module/OAuth/Revoke.php b/src/Module/OAuth/Revoke.php index 0604e90bf7..11d65420c0 100644 --- a/src/Module/OAuth/Revoke.php +++ b/src/Module/OAuth/Revoke.php @@ -26,6 +26,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; +use Friendica\Module\Special\HTTPException; use Psr\Http\Message\ResponseInterface; /** @@ -33,9 +34,9 @@ use Psr\Http\Message\ResponseInterface; */ class Revoke extends BaseApi { - public function run(array $request = [], bool $scopecheck = true): ResponseInterface + public function run(HTTPException $httpException, array $request = [], bool $scopecheck = true): ResponseInterface { - return parent::run($request, false); + return parent::run($httpException, $request, false); } protected function post(array $request = []) diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 1da8df18d5..14e9be7a69 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -26,6 +26,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; +use Friendica\Module\Special\HTTPException; use Friendica\Security\OAuth; use Friendica\Util\DateTimeFormat; use Psr\Http\Message\ResponseInterface; @@ -36,9 +37,9 @@ use Psr\Http\Message\ResponseInterface; */ class Token extends BaseApi { - public function run(array $request = [], bool $scopecheck = true): ResponseInterface + public function run(HTTPException $httpException, array $request = [], bool $scopecheck = true): ResponseInterface { - return parent::run($request, false); + return parent::run($httpException, $request, false); } protected function post(array $request = []) diff --git a/src/Module/Special/HTTPException.php b/src/Module/Special/HTTPException.php index 0cd7817ed4..6928cf810f 100644 --- a/src/Module/Special/HTTPException.php +++ b/src/Module/Special/HTTPException.php @@ -21,10 +21,13 @@ namespace Friendica\Module\Special; -use Friendica\Core\Logger; +use Friendica\App\Arguments; +use Friendica\App\Request; +use Friendica\Core\L10n; use Friendica\Core\Renderer; +use Friendica\Core\Session\Model\UserSession; use Friendica\Core\System; -use Friendica\DI; +use Psr\Log\LoggerInterface; /** * This special module displays HTTPException when they are thrown in modules. @@ -33,27 +36,52 @@ use Friendica\DI; */ class HTTPException { + /** @var L10n */ + protected $l10n; + /** @var LoggerInterface */ + protected $logger; + /** @var Arguments */ + protected $args; + /** @var bool */ + protected $isSiteAdmin; + /** @var array */ + protected $server; + /** @var string */ + protected $requestId; + + public function __construct(L10n $l10n, LoggerInterface $logger, Arguments $args, UserSession $session, Request $request, array $server = []) + { + $this->logger = $logger; + $this->l10n = $l10n; + $this->args = $args; + $this->isSiteAdmin = $session->isSiteAdmin(); + $this->server = $server; + $this->requestId = $request->getRequestId(); + } + /** * Generates the necessary template variables from the caught HTTPException. * * Fills in the blanks if title or descriptions aren't provided by the exception. * * @param \Friendica\Network\HTTPException $e + * * @return array ['$title' => ..., '$description' => ...] */ - private static function getVars(\Friendica\Network\HTTPException $e) + private function getVars(\Friendica\Network\HTTPException $e) { // Explanations are mostly taken from https://en.wikipedia.org/wiki/List_of_HTTP_status_codes $vars = [ - '$title' => $e->getDescription() ?: 'Error ' . $e->getCode(), - '$message' => $e->getMessage() ?: $e->getExplanation(), - '$back' => DI::l10n()->t('Go back'), - '$stack_trace' => DI::l10n()->t('Stack trace:'), + '$title' => $e->getDescription() ?: 'Error ' . $e->getCode(), + '$message' => $e->getMessage() ?: $e->getExplanation(), + '$back' => $this->l10n->t('Go back'), + '$stack_trace' => $this->l10n->t('Stack trace:'), + '$request_id' => $this->requestId, ]; - if (DI::app()->isSiteAdmin()) { - $vars['$thrown'] = DI::l10n()->t('Exception thrown in %s:%d', $e->getFile(), $e->getLine()); - $vars['$trace'] = $e->getTraceAsString(); + if ($this->isSiteAdmin) { + $vars['$thrown'] = $this->l10n->t('Exception thrown in %s:%d', $e->getFile(), $e->getLine()); + $vars['$trace'] = $e->getTraceAsString(); } return $vars; @@ -63,6 +91,7 @@ class HTTPException * Displays a bare message page with no theming at all. * * @param \Friendica\Network\HTTPException $e + * * @throws \Exception */ public function rawContent(\Friendica\Network\HTTPException $e) @@ -70,13 +99,13 @@ class HTTPException $content = ''; if ($e->getCode() >= 400) { - $vars = self::getVars($e); + $vars = $this->getVars($e); try { - $tpl = Renderer::getMarkupTemplate('http_status.tpl'); + $tpl = Renderer::getMarkupTemplate('http_status.tpl'); $content = Renderer::replaceMacros($tpl, $vars); } catch (\Exception $e) { $content = "

{$vars['$title']}

{$vars['$message']}

"; - if (DI::app()->isSiteAdmin()) { + if ($this->isSiteAdmin) { $content .= "

{$vars['$thrown']}

"; $content .= "
{$vars['$trace']}
"; } @@ -90,19 +119,28 @@ class HTTPException * Returns a content string that can be integrated in the current theme. * * @param \Friendica\Network\HTTPException $e + * * @return string * @throws \Exception */ public function content(\Friendica\Network\HTTPException $e): string { - header($_SERVER["SERVER_PROTOCOL"] . ' ' . $e->getCode() . ' ' . $e->getDescription()); + header($this->server['SERVER_PROTOCOL'] ?? 'HTTP/1.0' . ' ' . $e->getCode() . ' ' . $e->getDescription()); if ($e->getCode() >= 400) { - Logger::debug('Exit with error', ['code' => $e->getCode(), 'description' => $e->getDescription(), 'query' => DI::args()->getQueryString(), 'callstack' => System::callstack(20), 'method' => DI::args()->getMethod(), 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']); + $this->logger->debug('Exit with error', + [ + 'code' => $e->getCode(), + 'description' => $e->getDescription(), + 'query' => $this->args->getQueryString(), + 'callstack' => System::callstack(20), + 'method' => $this->args->getMethod(), + 'agent' => $this->server['HTTP_USER_AGENT'] ?? '' + ]); } $tpl = Renderer::getMarkupTemplate('exception.tpl'); - return Renderer::replaceMacros($tpl, self::getVars($e)); + return Renderer::replaceMacros($tpl, $this->getVars($e)); } } diff --git a/static/dependencies.config.php b/static/dependencies.config.php index fd242c3417..a4c52e0043 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -273,5 +273,10 @@ return [ ], \Psr\Clock\ClockInterface::class => [ 'instanceOf' => Util\Clock\SystemClock::class - ] + ], + \Friendica\Module\Special\HTTPException::class => [ + 'constructParams' => [ + $_SERVER + ], + ], ]; diff --git a/tests/src/Module/Api/ApiTest.php b/tests/src/Module/Api/ApiTest.php index 890bba19b6..c01f39f4c9 100644 --- a/tests/src/Module/Api/ApiTest.php +++ b/tests/src/Module/Api/ApiTest.php @@ -27,12 +27,14 @@ use Friendica\Core\Addon; use Friendica\Core\Hook; use Friendica\Database\Database; use Friendica\DI; +use Friendica\Module\Special\HTTPException; use Friendica\Security\Authentication; use Friendica\Security\BasicAuth; use Friendica\Test\FixtureTest; use Friendica\Test\Util\AppDouble; use Friendica\Test\Util\AuthenticationDouble; use Friendica\Test\Util\AuthTestConfig; +use Mockery\MockInterface; use Psr\Http\Message\ResponseInterface; abstract class ApiTest extends FixtureTest @@ -59,6 +61,9 @@ abstract class ApiTest extends FixtureTest 'nurl' => 'http://localhost/profile/othercontact' ]; + /** @var HTTPException */ + protected $httpExceptionMock; + // User ID that we know is not in the database const WRONG_USER_ID = 666; @@ -175,6 +180,8 @@ abstract class ApiTest extends FixtureTest // Manual override to bypass API authentication DI::app()->setIsLoggedIn(true); + $this->httpExceptionMock = $this->dice->create(HTTPException::class); + AuthTestConfig::$authenticated = true; AuthTestConfig::$user_id = 42; diff --git a/tests/src/Module/Api/Friendica/DirectMessages/SearchTest.php b/tests/src/Module/Api/Friendica/DirectMessages/SearchTest.php index 09845a99b4..9ec0f6f0dc 100644 --- a/tests/src/Module/Api/Friendica/DirectMessages/SearchTest.php +++ b/tests/src/Module/Api/Friendica/DirectMessages/SearchTest.php @@ -35,7 +35,7 @@ class SearchTest extends ApiTest $directMessage = new DirectMessage(new NullLogger(), DI::dba(), DI::twitterUser()); $response = (new Search($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); @@ -53,7 +53,7 @@ class SearchTest extends ApiTest $directMessage = new DirectMessage(new NullLogger(), DI::dba(), DI::twitterUser()); $response = (new Search($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'searchstring' => 'item_body' ]); @@ -74,7 +74,7 @@ class SearchTest extends ApiTest $directMessage = new DirectMessage(new NullLogger(), DI::dba(), DI::twitterUser()); $response = (new Search($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'searchstring' => 'test' ]); diff --git a/tests/src/Module/Api/Friendica/NotificationTest.php b/tests/src/Module/Api/Friendica/NotificationTest.php index 3c17471b03..1599b8abc1 100644 --- a/tests/src/Module/Api/Friendica/NotificationTest.php +++ b/tests/src/Module/Api/Friendica/NotificationTest.php @@ -67,7 +67,7 @@ class NotificationTest extends ApiTest XML; $response = (new Notification(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'xml'])) - ->run(); + ->run($this->httpExceptionMock); self::assertXmlStringEqualsXmlString($assertXml, (string)$response->getBody()); self::assertEquals([ @@ -79,7 +79,7 @@ XML; public function testWithJsonResult() { $response = (new Notification(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Friendica/Photo/DeleteTest.php b/tests/src/Module/Api/Friendica/Photo/DeleteTest.php index e3e208ff02..b946affe2b 100644 --- a/tests/src/Module/Api/Friendica/Photo/DeleteTest.php +++ b/tests/src/Module/Api/Friendica/Photo/DeleteTest.php @@ -39,7 +39,7 @@ class DeleteTest extends ApiTest public function testEmpty() { $this->expectException(BadRequestException::class); - (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))->run(); + (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))->run($this->httpExceptionMock); } public function testWithoutAuthenticatedUser() @@ -50,7 +50,7 @@ class DeleteTest extends ApiTest public function testWrong() { $this->expectException(BadRequestException::class); - (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))->run(['photo_id' => 1]); + (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))->run($this->httpExceptionMock, ['photo_id' => 1]); } public function testValidWithPost() @@ -58,7 +58,7 @@ class DeleteTest extends ApiTest $this->loadFixture(__DIR__ . '/../../../../../datasets/photo/photo.fixture.php', DI::dba()); $response = (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'photo_id' => '709057080661a283a6aa598501504178' ]); @@ -73,7 +73,7 @@ class DeleteTest extends ApiTest $this->loadFixture(__DIR__ . '/../../../../../datasets/photo/photo.fixture.php', DI::dba()); $response = (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'photo_id' => '709057080661a283a6aa598501504178' ]); diff --git a/tests/src/Module/Api/Friendica/Photoalbum/DeleteTest.php b/tests/src/Module/Api/Friendica/Photoalbum/DeleteTest.php index 6ce77f63aa..db16adfb90 100644 --- a/tests/src/Module/Api/Friendica/Photoalbum/DeleteTest.php +++ b/tests/src/Module/Api/Friendica/Photoalbum/DeleteTest.php @@ -40,7 +40,7 @@ class DeleteTest extends ApiTest { $this->expectException(BadRequestException::class); (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } @@ -48,7 +48,7 @@ class DeleteTest extends ApiTest { $this->expectException(BadRequestException::class); (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'album' => 'album_name' ]); } @@ -58,7 +58,7 @@ class DeleteTest extends ApiTest $this->loadFixture(__DIR__ . '/../../../../../datasets/photo/photo.fixture.php', DI::dba()); $response = (new Delete(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'album' => 'test_album'] ); diff --git a/tests/src/Module/Api/Friendica/Photoalbum/UpdateTest.php b/tests/src/Module/Api/Friendica/Photoalbum/UpdateTest.php index 5f25a62ac0..9a2b053dde 100644 --- a/tests/src/Module/Api/Friendica/Photoalbum/UpdateTest.php +++ b/tests/src/Module/Api/Friendica/Photoalbum/UpdateTest.php @@ -40,14 +40,14 @@ class UpdateTest extends ApiTest { $this->expectException(BadRequestException::class); (new Update(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } public function testTooFewArgs() { $this->expectException(BadRequestException::class); (new Update(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'album' => 'album_name' ]); } @@ -56,7 +56,7 @@ class UpdateTest extends ApiTest { $this->expectException(BadRequestException::class); (new Update(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'album' => 'album_name', 'album_new' => 'album_name' ]); @@ -72,7 +72,7 @@ class UpdateTest extends ApiTest $this->loadFixture(__DIR__ . '/../../../../../datasets/photo/photo.fixture.php', DI::dba()); $response = (new Update(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'album' => 'test_album', 'album_new' => 'test_album_2' ]); diff --git a/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php b/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php index 64d2a77826..52beb98019 100644 --- a/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php +++ b/tests/src/Module/Api/GnuSocial/GnuSocial/ConfigTest.php @@ -37,7 +37,7 @@ class ConfigTest extends ApiTest DI::config()->set('system', 'ssl_policy', BaseURL::SSL_POLICY_FULL); $response = (new Config(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); self::assertEquals('localhost', $json->site->server); diff --git a/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php b/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php index 175aaabda3..b0ec8f832e 100644 --- a/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php +++ b/tests/src/Module/Api/GnuSocial/GnuSocial/VersionTest.php @@ -31,7 +31,7 @@ class VersionTest extends ApiTest public function test() { $response = (new Version(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); self::assertEquals([ 'Content-type' => ['application/json'], diff --git a/tests/src/Module/Api/GnuSocial/Help/TestTest.php b/tests/src/Module/Api/GnuSocial/Help/TestTest.php index be0e187a63..47f6492b1e 100644 --- a/tests/src/Module/Api/GnuSocial/Help/TestTest.php +++ b/tests/src/Module/Api/GnuSocial/Help/TestTest.php @@ -31,7 +31,7 @@ class TestTest extends ApiTest public function testJson() { $response = (new Test(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); @@ -45,7 +45,7 @@ class TestTest extends ApiTest public function testXml() { $response = (new Test(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'xml'])) - ->run(); + ->run($this->httpExceptionMock); self::assertEquals([ 'Content-type' => ['text/xml'], diff --git a/tests/src/Module/Api/Mastodon/Accounts/VerifyCredentialsTest.php b/tests/src/Module/Api/Mastodon/Accounts/VerifyCredentialsTest.php index 5d3e33d132..daea2ca53e 100644 --- a/tests/src/Module/Api/Mastodon/Accounts/VerifyCredentialsTest.php +++ b/tests/src/Module/Api/Mastodon/Accounts/VerifyCredentialsTest.php @@ -36,7 +36,7 @@ class VerifyCredentialsTest extends ApiTest public function testApiAccountVerifyCredentials() { $response = (new VerifyCredentials(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php b/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php index 8d928b3ee3..ef566de2dd 100644 --- a/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php +++ b/tests/src/Module/Api/Twitter/Account/RateLimitStatusTest.php @@ -32,7 +32,7 @@ class RateLimitStatusTest extends ApiTest public function testWithJson() { $response = (new RateLimitStatus(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); $result = $this->toJson($response); @@ -48,7 +48,7 @@ class RateLimitStatusTest extends ApiTest public function testWithXml() { $response = (new RateLimitStatus(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'xml'])) - ->run(); + ->run($this->httpExceptionMock); self::assertEquals([ 'Content-type' => ['text/xml'], diff --git a/tests/src/Module/Api/Twitter/Account/UpdateProfileTest.php b/tests/src/Module/Api/Twitter/Account/UpdateProfileTest.php index d3c8f93024..abdde24861 100644 --- a/tests/src/Module/Api/Twitter/Account/UpdateProfileTest.php +++ b/tests/src/Module/Api/Twitter/Account/UpdateProfileTest.php @@ -36,7 +36,7 @@ class UpdateProfileTest extends ApiTest $this->useHttpMethod(Router::POST); $response = (new UpdateProfile(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'name' => 'new_name', 'description' => 'new_description' ]); diff --git a/tests/src/Module/Api/Twitter/Blocks/ListsTest.php b/tests/src/Module/Api/Twitter/Blocks/ListsTest.php index 1212a3f8e9..30d42414d4 100644 --- a/tests/src/Module/Api/Twitter/Blocks/ListsTest.php +++ b/tests/src/Module/Api/Twitter/Blocks/ListsTest.php @@ -34,7 +34,7 @@ class ListsTest extends ApiTest public function testApiStatusesFWithBlocks() { $response = (new Lists(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/DirectMessages/AllTest.php b/tests/src/Module/Api/Twitter/DirectMessages/AllTest.php index 666299cc69..6d74b87128 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/AllTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/AllTest.php @@ -40,7 +40,7 @@ class AllTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new All($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/DirectMessages/ConversationTest.php b/tests/src/Module/Api/Twitter/DirectMessages/ConversationTest.php index e895845aad..834a5150e0 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/ConversationTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/ConversationTest.php @@ -39,7 +39,7 @@ class ConversationTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new Conversation($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'friendica_verbose' => true, ]); diff --git a/tests/src/Module/Api/Twitter/DirectMessages/DestroyTest.php b/tests/src/Module/Api/Twitter/DirectMessages/DestroyTest.php index b9317190b6..2145905379 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/DestroyTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/DestroyTest.php @@ -38,7 +38,7 @@ class DestroyTest extends ApiTest { $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class); (new Destroy(DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -49,7 +49,7 @@ class DestroyTest extends ApiTest public function testApiDirectMessagesDestroyWithVerbose() { $response = (new Destroy(DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'friendica_verbose' => true, ]); @@ -85,7 +85,7 @@ class DestroyTest extends ApiTest { $this->expectException(\Friendica\Network\HTTPException\BadRequestException::class); (new Destroy(DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 1 ]); } @@ -98,7 +98,7 @@ class DestroyTest extends ApiTest public function testApiDirectMessagesDestroyWithIdAndVerbose() { $response = (new Destroy(DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 1, 'friendica_parenturi' => 'parent_uri', 'friendica_verbose' => true, @@ -122,7 +122,7 @@ class DestroyTest extends ApiTest $id = $ids[0]['id']; $response = (new Destroy(DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => $id, 'friendica_verbose' => true, ]); diff --git a/tests/src/Module/Api/Twitter/DirectMessages/InboxTest.php b/tests/src/Module/Api/Twitter/DirectMessages/InboxTest.php index cee1450cf7..f239755b3e 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/InboxTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/InboxTest.php @@ -41,7 +41,7 @@ class InboxTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new Inbox($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php b/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php index cab3c22026..2b473fb48b 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/NewDMTest.php @@ -39,7 +39,7 @@ class NewDMTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new NewDM($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); self::assertEmpty((string)$response->getBody()); } @@ -71,7 +71,7 @@ class NewDMTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new NewDM($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'text' => 'message_text', 'user_id' => 43 ]); @@ -93,7 +93,7 @@ class NewDMTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new NewDM($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'text' => 'message_text', 'user_id' => 44 ]); @@ -117,7 +117,7 @@ class NewDMTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new NewDM($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'text' => 'message_text', 'user_id' => 44, 'title' => 'message_title', @@ -143,7 +143,7 @@ class NewDMTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new NewDM($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'rss'])) - ->run([ + ->run($this->httpExceptionMock, [ 'text' => 'message_text', 'user_id' => 44, 'title' => 'message_title', diff --git a/tests/src/Module/Api/Twitter/DirectMessages/SentTest.php b/tests/src/Module/Api/Twitter/DirectMessages/SentTest.php index 9c498af5f6..f63a24f806 100644 --- a/tests/src/Module/Api/Twitter/DirectMessages/SentTest.php +++ b/tests/src/Module/Api/Twitter/DirectMessages/SentTest.php @@ -39,7 +39,7 @@ class SentTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new Sent($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run([ + ->run($this->httpExceptionMock, [ 'friendica_verbose' => true, ]); @@ -59,7 +59,7 @@ class SentTest extends ApiTest $directMessage = new DirectMessage(DI::logger(), DI::dba(), DI::twitterUser()); $response = (new Sent($directMessage, DI::dba(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'rss'])) - ->run(); + ->run($this->httpExceptionMock); self::assertXml((string)$response->getBody(), 'direct-messages'); } diff --git a/tests/src/Module/Api/Twitter/Favorites/CreateTest.php b/tests/src/Module/Api/Twitter/Favorites/CreateTest.php index 61e235700c..fd0f86b6aa 100644 --- a/tests/src/Module/Api/Twitter/Favorites/CreateTest.php +++ b/tests/src/Module/Api/Twitter/Favorites/CreateTest.php @@ -47,7 +47,7 @@ class CreateTest extends ApiTest $this->expectException(BadRequestException::class); (new Create(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -58,7 +58,7 @@ class CreateTest extends ApiTest public function testApiFavoritesCreateDestroyWithCreateAction() { $response = (new Create(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 3 ]); @@ -75,7 +75,7 @@ class CreateTest extends ApiTest public function testApiFavoritesCreateDestroyWithCreateActionAndRss() { $response = (new Create(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => ICanCreateResponses::TYPE_RSS])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 3 ]); diff --git a/tests/src/Module/Api/Twitter/Favorites/DestroyTest.php b/tests/src/Module/Api/Twitter/Favorites/DestroyTest.php index bb7b54ee42..e65c120142 100644 --- a/tests/src/Module/Api/Twitter/Favorites/DestroyTest.php +++ b/tests/src/Module/Api/Twitter/Favorites/DestroyTest.php @@ -46,7 +46,7 @@ class DestroyTest extends ApiTest $this->expectException(BadRequestException::class); (new Destroy(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -57,7 +57,7 @@ class DestroyTest extends ApiTest public function testApiFavoritesCreateDestroyWithDestroyAction() { $response = (new Destroy(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 3 ]); diff --git a/tests/src/Module/Api/Twitter/FavoritesTest.php b/tests/src/Module/Api/Twitter/FavoritesTest.php index 6da92e667d..c95aff6917 100644 --- a/tests/src/Module/Api/Twitter/FavoritesTest.php +++ b/tests/src/Module/Api/Twitter/FavoritesTest.php @@ -37,7 +37,7 @@ class FavoritesTest extends ApiTest public function testApiFavorites() { $response = (new Favorites(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'page' => -1, 'max_id' => 10, ]); @@ -58,7 +58,7 @@ class FavoritesTest extends ApiTest { $response = (new Favorites(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], [ 'extension' => ICanCreateResponses::TYPE_RSS - ]))->run(); + ]))->run($this->httpExceptionMock); self::assertEquals(ICanCreateResponses::TYPE_RSS, $response->getHeaderLine(ICanCreateResponses::X_HEADER)); diff --git a/tests/src/Module/Api/Twitter/Followers/ListsTest.php b/tests/src/Module/Api/Twitter/Followers/ListsTest.php index 02e2745492..f48916ce80 100644 --- a/tests/src/Module/Api/Twitter/Followers/ListsTest.php +++ b/tests/src/Module/Api/Twitter/Followers/ListsTest.php @@ -34,7 +34,7 @@ class ListsTest extends ApiTest public function testApiStatusesFWithFollowers() { $response = (new Lists(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/Friends/ListsTest.php b/tests/src/Module/Api/Twitter/Friends/ListsTest.php index 07fdc891f3..53d8d8d866 100644 --- a/tests/src/Module/Api/Twitter/Friends/ListsTest.php +++ b/tests/src/Module/Api/Twitter/Friends/ListsTest.php @@ -36,7 +36,7 @@ class ListsTest extends ApiTest public function testApiStatusesFWithFriends() { $response = (new Lists(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/Friendships/IncomingTest.php b/tests/src/Module/Api/Twitter/Friendships/IncomingTest.php index 89a296b066..f93375b14e 100644 --- a/tests/src/Module/Api/Twitter/Friendships/IncomingTest.php +++ b/tests/src/Module/Api/Twitter/Friendships/IncomingTest.php @@ -36,7 +36,7 @@ class IncomingTest extends ApiTest public function testApiFriendshipsIncoming() { $response = (new Incoming(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/Lists/StatusesTest.php b/tests/src/Module/Api/Twitter/Lists/StatusesTest.php index 8bc8257c0c..f642181533 100644 --- a/tests/src/Module/Api/Twitter/Lists/StatusesTest.php +++ b/tests/src/Module/Api/Twitter/Lists/StatusesTest.php @@ -39,7 +39,7 @@ class StatusesTest extends ApiTest $this->expectException(BadRequestException::class); (new Statuses(DI::dba(), DI::twitterStatus(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -48,7 +48,7 @@ class StatusesTest extends ApiTest public function testApiListsStatusesWithListId() { $response = (new Statuses(DI::dba(), DI::twitterStatus(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'list_id' => 1, 'page' => -1, 'max_id' => 10 @@ -68,7 +68,7 @@ class StatusesTest extends ApiTest public function testApiListsStatusesWithListIdAndRss() { $response = (new Statuses(DI::dba(), DI::twitterStatus(), DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'rss'])) - ->run([ + ->run($this->httpExceptionMock, [ 'list_id' => 1 ]); diff --git a/tests/src/Module/Api/Twitter/Media/UploadTest.php b/tests/src/Module/Api/Twitter/Media/UploadTest.php index 7d64971917..f1930e2444 100644 --- a/tests/src/Module/Api/Twitter/Media/UploadTest.php +++ b/tests/src/Module/Api/Twitter/Media/UploadTest.php @@ -47,7 +47,7 @@ class UploadTest extends ApiTest $this->expectException(BadRequestException::class); (new Upload(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -61,7 +61,7 @@ class UploadTest extends ApiTest AuthTestConfig::$authenticated = false; (new Upload(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -80,7 +80,7 @@ class UploadTest extends ApiTest ]; (new Upload(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -103,7 +103,7 @@ class UploadTest extends ApiTest ]; $response = (new Upload(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $media = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/SavedSearchesTest.php b/tests/src/Module/Api/Twitter/SavedSearchesTest.php index 1d6e140bd1..ab03919c99 100644 --- a/tests/src/Module/Api/Twitter/SavedSearchesTest.php +++ b/tests/src/Module/Api/Twitter/SavedSearchesTest.php @@ -31,7 +31,7 @@ class SavedSearchesTest extends ApiTest public function test() { $response = (new SavedSearches(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => 'json'])) - ->run(); + ->run($this->httpExceptionMock); $result = $this->toJson($response); diff --git a/tests/src/Module/Api/Twitter/Statuses/DestroyTest.php b/tests/src/Module/Api/Twitter/Statuses/DestroyTest.php index 68ec195ce3..4a29525578 100644 --- a/tests/src/Module/Api/Twitter/Statuses/DestroyTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/DestroyTest.php @@ -46,7 +46,7 @@ class DestroyTest extends ApiTest $this->expectException(BadRequestException::class); (new Destroy(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -72,7 +72,7 @@ class DestroyTest extends ApiTest public function testApiStatusesDestroyWithId() { $response = (new Destroy(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 1 ]); diff --git a/tests/src/Module/Api/Twitter/Statuses/MentionsTest.php b/tests/src/Module/Api/Twitter/Statuses/MentionsTest.php index 0bb694528d..59daef80c7 100644 --- a/tests/src/Module/Api/Twitter/Statuses/MentionsTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/MentionsTest.php @@ -37,7 +37,7 @@ class MentionsTest extends ApiTest public function testApiStatusesMentions() { $response = (new Mentions(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'max_id' => 10 ]); @@ -55,7 +55,7 @@ class MentionsTest extends ApiTest public function testApiStatusesMentionsWithNegativePage() { $response = (new Mentions(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'page' => -2 ]); @@ -87,7 +87,7 @@ class MentionsTest extends ApiTest public function testApiStatusesMentionsWithRss() { $response = (new Mentions(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], ['extension' => ICanCreateResponses::TYPE_RSS])) - ->run([ + ->run($this->httpExceptionMock, [ 'page' => -2 ]); diff --git a/tests/src/Module/Api/Twitter/Statuses/NetworkPublicTimelineTest.php b/tests/src/Module/Api/Twitter/Statuses/NetworkPublicTimelineTest.php index a09cd44d1e..542cb28bac 100644 --- a/tests/src/Module/Api/Twitter/Statuses/NetworkPublicTimelineTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/NetworkPublicTimelineTest.php @@ -37,7 +37,7 @@ class NetworkPublicTimelineTest extends ApiTest public function testApiStatusesNetworkpublicTimeline() { $response = (new NetworkPublicTimeline(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'max_id' => 10 ]); @@ -59,7 +59,7 @@ class NetworkPublicTimelineTest extends ApiTest public function testApiStatusesNetworkpublicTimelineWithNegativePage() { $response = (new NetworkPublicTimeline(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'page' => -2 ]); @@ -96,7 +96,7 @@ class NetworkPublicTimelineTest extends ApiTest { $response = (new NetworkPublicTimeline(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], [ 'extension' => ICanCreateResponses::TYPE_RSS - ]))->run([ + ]))->run($this->httpExceptionMock, [ 'page' => -2 ]); diff --git a/tests/src/Module/Api/Twitter/Statuses/RetweetTest.php b/tests/src/Module/Api/Twitter/Statuses/RetweetTest.php index f2c99baa8f..9f498b6920 100644 --- a/tests/src/Module/Api/Twitter/Statuses/RetweetTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/RetweetTest.php @@ -46,7 +46,7 @@ class RetweetTest extends ApiTest $this->expectException(BadRequestException::class); (new Retweet(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -72,7 +72,7 @@ class RetweetTest extends ApiTest public function testApiStatusesRepeatWithId() { $response = (new Retweet(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 1 ]); @@ -89,7 +89,7 @@ class RetweetTest extends ApiTest public function testApiStatusesRepeatWithSharedId() { $response = (new Retweet(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 5 ]); diff --git a/tests/src/Module/Api/Twitter/Statuses/ShowTest.php b/tests/src/Module/Api/Twitter/Statuses/ShowTest.php index 656aa5e91a..df284df2ae 100644 --- a/tests/src/Module/Api/Twitter/Statuses/ShowTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/ShowTest.php @@ -40,7 +40,7 @@ class ShowTest extends ApiTest (new Show(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -51,7 +51,7 @@ class ShowTest extends ApiTest public function testApiStatusesShowWithId() { $response = (new Show(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 1 ]); @@ -69,7 +69,7 @@ class ShowTest extends ApiTest public function testApiStatusesShowWithConversation() { $response = (new Show(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'id' => 1, 'conversation' => 1 ]); diff --git a/tests/src/Module/Api/Twitter/Statuses/UpdateTest.php b/tests/src/Module/Api/Twitter/Statuses/UpdateTest.php index 92ca0702e3..4754a34d7e 100644 --- a/tests/src/Module/Api/Twitter/Statuses/UpdateTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/UpdateTest.php @@ -55,7 +55,7 @@ class UpdateTest extends ApiTest ]; $response = (new Update(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'status' => 'Status content #friendica', 'in_reply_to_status_id' => 0, 'lat' => 48, @@ -77,7 +77,7 @@ class UpdateTest extends ApiTest public function testApiStatusesUpdateWithHtml() { $response = (new Update(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'htmlstatus' => 'Status content', ]); diff --git a/tests/src/Module/Api/Twitter/Statuses/UserTimelineTest.php b/tests/src/Module/Api/Twitter/Statuses/UserTimelineTest.php index 078a88f96f..240ebc8e8e 100644 --- a/tests/src/Module/Api/Twitter/Statuses/UserTimelineTest.php +++ b/tests/src/Module/Api/Twitter/Statuses/UserTimelineTest.php @@ -37,7 +37,7 @@ class UserTimelineTest extends ApiTest public function testApiStatusesUserTimeline() { $response = (new UserTimeline(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'user_id' => 42, 'max_id' => 10, 'exclude_replies' => true, @@ -62,7 +62,7 @@ class UserTimelineTest extends ApiTest public function testApiStatusesUserTimelineWithNegativePage() { $response = (new UserTimeline(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'user_id' => 42, 'page' => -2, ]); @@ -86,7 +86,7 @@ class UserTimelineTest extends ApiTest { $response = (new UserTimeline(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], [ 'extension' => ICanCreateResponses::TYPE_RSS - ]))->run(); + ]))->run($this->httpExceptionMock); self::assertEquals(ICanCreateResponses::TYPE_RSS, $response->getHeaderLine(ICanCreateResponses::X_HEADER)); diff --git a/tests/src/Module/Api/Twitter/Users/LookupTest.php b/tests/src/Module/Api/Twitter/Users/LookupTest.php index 9b5134fd8a..677e53df55 100644 --- a/tests/src/Module/Api/Twitter/Users/LookupTest.php +++ b/tests/src/Module/Api/Twitter/Users/LookupTest.php @@ -39,7 +39,7 @@ class LookupTest extends ApiTest $this->expectException(NotFoundException::class); (new Lookup(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } /** @@ -50,7 +50,7 @@ class LookupTest extends ApiTest public function testApiUsersLookupWithUserId() { $respone = (new Lookup(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'user_id' => static::OTHER_USER['id'] ]); diff --git a/tests/src/Module/Api/Twitter/Users/SearchTest.php b/tests/src/Module/Api/Twitter/Users/SearchTest.php index 903bbe9fda..0c816b5ab9 100644 --- a/tests/src/Module/Api/Twitter/Users/SearchTest.php +++ b/tests/src/Module/Api/Twitter/Users/SearchTest.php @@ -38,7 +38,7 @@ class SearchTest extends ApiTest public function testApiUsersSearch() { $respone = (new Search(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run([ + ->run($this->httpExceptionMock, [ 'q' => static::OTHER_USER['name'] ]); @@ -56,7 +56,7 @@ class SearchTest extends ApiTest { $respone = (new Search(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], [ 'extension' => ICanCreateResponses::TYPE_XML - ]))->run([ + ]))->run($this->httpExceptionMock, [ 'q' => static::OTHER_USER['name'] ]); @@ -73,6 +73,6 @@ class SearchTest extends ApiTest $this->expectException(BadRequestException::class); (new Search(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); } } diff --git a/tests/src/Module/Api/Twitter/Users/ShowTest.php b/tests/src/Module/Api/Twitter/Users/ShowTest.php index 703ad4f6cb..3cec455352 100644 --- a/tests/src/Module/Api/Twitter/Users/ShowTest.php +++ b/tests/src/Module/Api/Twitter/Users/ShowTest.php @@ -37,7 +37,7 @@ class ShowTest extends ApiTest public function testApiUsersShow() { $response = (new Show(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [])) - ->run(); + ->run($this->httpExceptionMock); $json = $this->toJson($response); @@ -58,7 +58,7 @@ class ShowTest extends ApiTest { $response = (new Show(DI::app(), DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], [ 'extension' => ICanCreateResponses::TYPE_XML - ]))->run(); + ]))->run($this->httpExceptionMock); self::assertEquals(ICanCreateResponses::TYPE_XML, $response->getHeaderLine(ICanCreateResponses::X_HEADER)); diff --git a/tests/src/Module/NodeInfoTest.php b/tests/src/Module/NodeInfoTest.php index a7766d2472..101ee021c7 100644 --- a/tests/src/Module/NodeInfoTest.php +++ b/tests/src/Module/NodeInfoTest.php @@ -27,14 +27,26 @@ use Friendica\DI; use Friendica\Module\NodeInfo110; use Friendica\Module\NodeInfo120; use Friendica\Module\NodeInfo210; +use Friendica\Module\Special\HTTPException; use Friendica\Test\FixtureTest; +use Mockery\MockInterface; class NodeInfoTest extends FixtureTest { + /** @var MockInterface|HTTPException */ + protected $httpExceptionMock; + + protected function setUp(): void + { + parent::setUp(); + + $this->httpExceptionMock = \Mockery::mock(HTTPException::class); + } + public function testNodeInfo110() { $response = (new NodeInfo110(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), DI::config(), [])) - ->run(); + ->run($this->httpExceptionMock); self::assertJson($response->getBody()); self::assertEquals(['Content-type' => ['application/json'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders()); @@ -55,7 +67,7 @@ class NodeInfoTest extends FixtureTest public function testNodeInfo120() { $response = (new NodeInfo120(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), DI::config(), [])) - ->run(); + ->run($this->httpExceptionMock); self::assertJson($response->getBody()); self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders()); @@ -75,7 +87,7 @@ class NodeInfoTest extends FixtureTest public function testNodeInfo210() { $response = (new NodeInfo210(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), DI::config(), [])) - ->run(); + ->run($this->httpExceptionMock); self::assertJson($response->getBody()); self::assertEquals(['Content-type' => ['application/json; charset=utf-8'], ICanCreateResponses::X_HEADER => ['json']], $response->getHeaders()); diff --git a/tests/src/Module/Special/OptionsTest.php b/tests/src/Module/Special/OptionsTest.php index 62ad1b3de2..cd16720505 100644 --- a/tests/src/Module/Special/OptionsTest.php +++ b/tests/src/Module/Special/OptionsTest.php @@ -24,16 +24,28 @@ namespace Friendica\Test\src\Module\Special; use Friendica\App\Router; use Friendica\Capabilities\ICanCreateResponses; use Friendica\DI; +use Friendica\Module\Special\HTTPException; use Friendica\Module\Special\Options; use Friendica\Test\FixtureTest; +use Mockery\MockInterface; class OptionsTest extends FixtureTest { + /** @var MockInterface|HTTPException */ + protected $httpExceptionMock; + + protected function setUp(): void + { + parent::setUp(); + + $this->httpExceptionMock = \Mockery::mock(HTTPException::class); + } + public function testOptionsAll() { $this->useHttpMethod(Router::OPTIONS); - $response = (new Options(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))->run(); + $response = (new Options(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), []))->run($this->httpExceptionMock); self::assertEmpty((string)$response->getBody()); self::assertEquals(204, $response->getStatusCode()); @@ -51,7 +63,7 @@ class OptionsTest extends FixtureTest $response = (new Options(DI::l10n(), DI::baseUrl(), DI::args(), DI::logger(), DI::profiler(), DI::apiResponse(), [], [ 'AllowedMethods' => [Router::GET, Router::POST], - ]))->run(); + ]))->run($this->httpExceptionMock); self::assertEmpty((string)$response->getBody()); self::assertEquals(204, $response->getStatusCode()); diff --git a/view/templates/exception.tpl b/view/templates/exception.tpl index ad1a15f878..3499a5cb15 100644 --- a/view/templates/exception.tpl +++ b/view/templates/exception.tpl @@ -7,6 +7,9 @@ {{$stack_trace}} {{$trace}} {{/if}} +{{if $request_id}} +
Request: {{$request_id}}
+{{/if}} {{if $back}}

{{/if}} diff --git a/view/templates/http_status.tpl b/view/templates/http_status.tpl index a9c094c4b2..874bf96691 100644 --- a/view/templates/http_status.tpl +++ b/view/templates/http_status.tpl @@ -8,5 +8,8 @@ {{if $trace}}
{{$trace nofilter}}
{{/if}} + {{if $request_id}} +
Request: {{$request_id}}
+ {{/if}} From 1dfe0fc6034cf48b4c6d844766c07a242a8e6aa6 Mon Sep 17 00:00:00 2001 From: Philipp Date: Sun, 25 Dec 2022 20:43:08 +0100 Subject: [PATCH 5/5] adapt examples --- mods/sample-nginx-reverse-proxy.config | 20 ++++++++++++++++++++ mods/sample-nginx.config | 22 ++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/mods/sample-nginx-reverse-proxy.config b/mods/sample-nginx-reverse-proxy.config index afc74dfc4a..e5faa64034 100644 --- a/mods/sample-nginx-reverse-proxy.config +++ b/mods/sample-nginx-reverse-proxy.config @@ -15,6 +15,25 @@ # ----- ... + +## +# by https://syshero.org/2018-04-13-nginx-unique-request-identifier/ +# if X-Request-ID is set, NGINX will forward the same value to the next upstream +# if the header is not set, NGINX will generate a random request identifier and add it to the request. +# +# To guarantee backward compatibility, map to format the $request_id variable to a format that matches any old setups. +## + +map $request_id $formatted_id { + "~*(?[0-9a-f]{8})(?[0-9a-f]{4})(?[0-9a-f]{4})(?[0-9a-f]{4})(?.*)$" "${p1}-${p2}-${p3}-${p4}-${p5}"; +} + +map $http_x_request_id $uuid { + default "${request_id}"; + ~* "${http_x_request_id}"; +} + + server { ... @@ -30,6 +49,7 @@ server { proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Forwarded "for=$proxy_add_x_forwarded_for; proto=$scheme"; + proxy_set_header X-Request-ID $uuid; } ... diff --git a/mods/sample-nginx.config b/mods/sample-nginx.config index 5530bfaefd..88edf19162 100644 --- a/mods/sample-nginx.config +++ b/mods/sample-nginx.config @@ -20,6 +20,24 @@ # http://wiki.nginx.org/Configuration ## +## +# by https://syshero.org/2018-04-13-nginx-unique-request-identifier/ +# if X-Request-ID is set, NGINX will forward the same value to the next upstream +# if the header is not set, NGINX will generate a random request identifier and add it to the request. +# +# To guarantee backward compatibility, map to format the $request_id variable to a format that matches any old setups. +## + +map $request_id $formatted_id { + "~*(?[0-9a-f]{8})(?[0-9a-f]{4})(?[0-9a-f]{4})(?[0-9a-f]{4})(?.*)$" "${p1}-${p2}-${p3}-${p4}-${p5}"; +} + +map $http_x_request_id $uuid { + default "${request_id}"; + ~* "${http_x_request_id}"; +} + + ## # This configuration assumes your domain is example.net # You have a separate subdomain friendica.example.net @@ -80,6 +98,9 @@ server { client_max_body_size 20m; client_body_buffer_size 128k; + # add the request id header to show it in the HTTP header output + add_header X-Request-ID $uuid; + # rewrite to front controller as default rule location / { try_files $uri /index.php?pagename=$uri&$args; @@ -125,6 +146,7 @@ server { include fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + fastcgi_param HTTP_X_REQUEST_ID $uuid; fastcgi_buffers 16 16k; fastcgi_buffer_size 32k;