From 4236a9a1059411c1d6483f772af30322ce713f0e Mon Sep 17 00:00:00 2001 From: Michael Date: Fri, 29 Oct 2021 23:21:07 +0000 Subject: [PATCH] Improved http error handling --- bin/auth_ejabberd.php | 5 ++- bin/console.php | 5 ++- bin/daemon.php | 5 ++- bin/testargs.php | 5 ++- bin/wait-for-connection | 5 ++- bin/worker.php | 5 ++- include/api.php | 2 - src/App/Module.php | 4 +- src/Core/Cache/TraitMemcacheCommand.php | 8 ++-- src/Core/Renderer.php | 18 ++++----- src/Core/System.php | 39 +++++++++++-------- src/Database/Database.php | 4 +- src/Factory/Api/Mastodon/Application.php | 6 +-- src/Module/Admin/Summary.php | 7 ++-- src/Module/Diaspora/Receive.php | 4 +- src/Module/Friendica.php | 1 + src/Module/Photo.php | 4 +- src/Module/Proxy.php | 4 +- src/Module/Special/HTTPException.php | 37 ++++-------------- src/Network/CurlResult.php | 9 ++--- src/Network/HTTPException.php | 8 +--- .../HTTPException/AcceptedException.php | 1 + .../HTTPException/BadGatewayException.php | 4 +- .../HTTPException/BadRequestException.php | 4 +- .../HTTPException/ConflictException.php | 4 +- .../ExpectationFailedException.php | 4 +- .../HTTPException/ForbiddenException.php | 4 +- src/Network/HTTPException/FoundException.php | 30 ++++++++++++++ .../HTTPException/GatewayTimeoutException.php | 4 +- src/Network/HTTPException/GoneException.php | 4 +- .../HTTPException/ImATeapotException.php | 5 ++- .../InternalServerErrorException.php | 4 +- .../HTTPException/LenghtRequiredException.php | 4 +- .../MethodNotAllowedException.php | 4 +- .../HTTPException/MovedPermanently.php | 30 ++++++++++++++ .../HTTPException/NoContentException.php | 1 + .../HTTPException/NonAcceptableException.php | 4 +- .../HTTPException/NotFoundException.php | 4 +- .../HTTPException/NotImplementedException.php | 4 +- .../HTTPException/NotModifiedException.php | 30 ++++++++++++++ src/Network/HTTPException/OKException.php | 1 + .../PreconditionFailedException.php | 4 +- .../ServiceUnavailableException.php | 4 +- .../TemporaryRedirectException.php | 30 ++++++++++++++ .../TooManyRequestsException.php | 4 +- .../HTTPException/UnauthorizedException.php | 4 +- .../UnprocessableEntityException.php | 4 +- .../UnsupportedMediaTypeException.php | 4 +- src/Render/FriendicaSmartyEngine.php | 4 +- src/Util/EMailer/MailBuilder.php | 8 ++-- src/Util/HTTPSignature.php | 2 +- src/Util/Network.php | 4 +- src/Worker/Notifier.php | 2 +- view/theme/frio/style.php | 4 +- view/theme/vier/style.php | 4 +- 55 files changed, 282 insertions(+), 135 deletions(-) create mode 100644 src/Network/HTTPException/FoundException.php create mode 100644 src/Network/HTTPException/MovedPermanently.php create mode 100644 src/Network/HTTPException/NotModifiedException.php create mode 100644 src/Network/HTTPException/TemporaryRedirectException.php diff --git a/bin/auth_ejabberd.php b/bin/auth_ejabberd.php index 88e5d034c..fd1b40cc8 100755 --- a/bin/auth_ejabberd.php +++ b/bin/auth_ejabberd.php @@ -51,9 +51,10 @@ * */ +use Friendica\Network\HTTPException\ForbiddenException; + if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); - exit(); + throw new ForbiddenException(); } use Dice\Dice; diff --git a/bin/console.php b/bin/console.php index 35f0b5fee..edfb8cd28 100755 --- a/bin/console.php +++ b/bin/console.php @@ -20,9 +20,10 @@ * */ +use Friendica\Network\HTTPException\ForbiddenException; + if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); - exit(); + throw new ForbiddenException(); } use Dice\Dice; diff --git a/bin/daemon.php b/bin/daemon.php index 7d4945fe0..965c495ec 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -23,9 +23,10 @@ * This script was taken from http://php.net/manual/en/function.pcntl-fork.php */ +use Friendica\Network\HTTPException\ForbiddenException; + if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); - exit(); + throw new ForbiddenException(); } use Dice\Dice; diff --git a/bin/testargs.php b/bin/testargs.php index 55197f63a..05826f2e4 100644 --- a/bin/testargs.php +++ b/bin/testargs.php @@ -26,9 +26,10 @@ * */ +use Friendica\Network\HTTPException\ForbiddenException; + if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); - exit(); + throw new ForbiddenException(); } if (($_SERVER["argc"] > 1) && isset($_SERVER["argv"][1])) { diff --git a/bin/wait-for-connection b/bin/wait-for-connection index f0fd8cc60..35560feb2 100755 --- a/bin/wait-for-connection +++ b/bin/wait-for-connection @@ -24,9 +24,10 @@ * Usage: php bin/wait-for-connection {HOST} {PORT} [{TIMEOUT}] */ +use Friendica\Network\HTTPException\ForbiddenException; + if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); - exit(); + throw new ForbiddenException(); } $timeout = 60; diff --git a/bin/worker.php b/bin/worker.php index 2fe03cb4b..a39d04963 100755 --- a/bin/worker.php +++ b/bin/worker.php @@ -21,9 +21,10 @@ * Starts the background processing */ +use Friendica\Network\HTTPException\ForbiddenException; + if (php_sapi_name() !== 'cli') { - header($_SERVER["SERVER_PROTOCOL"] . ' 403 Forbidden'); - exit(); + throw new ForbiddenException(); } use Dice\Dice; diff --git a/include/api.php b/include/api.php index 22a6ee432..fc73ae850 100644 --- a/include/api.php +++ b/include/api.php @@ -246,8 +246,6 @@ function api_login(App $a) if (!DBA::isResult($record)) { Logger::debug(API_LOG_PREFIX . 'failed', ['module' => 'api', 'action' => 'login', 'parameters' => $_SERVER]); header('WWW-Authenticate: Basic realm="Friendica"'); - //header('HTTP/1.0 401 Unauthorized'); - //die('This api requires login'); throw new UnauthorizedException("This API requires login"); } diff --git a/src/App/Module.php b/src/App/Module.php index f15b1236e..a5fddb206 100644 --- a/src/App/Module.php +++ b/src/App/Module.php @@ -29,6 +29,7 @@ use Friendica\Module\Home; use Friendica\Module\HTTPException\MethodNotAllowed; use Friendica\Module\HTTPException\PageNotFound; use Friendica\Network\HTTPException\MethodNotAllowedException; +use Friendica\Network\HTTPException\NoContentException; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -291,9 +292,8 @@ class Module // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS // @todo Check allowed methods per requested path if ($server['REQUEST_METHOD'] === Router::OPTIONS) { - header('HTTP/1.1 204 No Content'); header('Allow: ' . implode(',', Router::ALLOWED_METHODS)); - exit(); + throw new NoContentException(); } $placeholder = ''; diff --git a/src/Core/Cache/TraitMemcacheCommand.php b/src/Core/Cache/TraitMemcacheCommand.php index abc41ceea..3eaae2c15 100644 --- a/src/Core/Cache/TraitMemcacheCommand.php +++ b/src/Core/Cache/TraitMemcacheCommand.php @@ -21,7 +21,7 @@ namespace Friendica\Core\Cache; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\ServiceUnavailableException; /** * Trait for Memcache to add a custom version of the @@ -52,7 +52,7 @@ trait TraitMemcacheCommand * * @return array All keys of the memcache instance * - * @throws InternalServerErrorException + * @throws ServiceUnavailableException */ protected function getMemcacheKeys() { @@ -88,13 +88,13 @@ trait TraitMemcacheCommand * * @return string The returned buffer result * - * @throws InternalServerErrorException In case the memcache server isn't available (anymore) + * @throws ServiceUnavailableException In case the memcache server isn't available (anymore) */ protected function sendMemcacheCommand(string $command) { $s = @fsockopen($this->server, $this->port); if (!$s) { - throw new InternalServerErrorException("Cant connect to:" . $this->server . ':' . $this->port); + throw new ServiceUnavailableException("Cant connect to:" . $this->server . ':' . $this->port); } fwrite($s, $command . "\r\n"); diff --git a/src/Core/Renderer.php b/src/Core/Renderer.php index ad1717ae8..4eb408472 100644 --- a/src/Core/Renderer.php +++ b/src/Core/Renderer.php @@ -23,7 +23,7 @@ namespace Friendica\Core; use Exception; use Friendica\DI; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\ServiceUnavailableException; use Friendica\Render\TemplateEngine; /** @@ -69,7 +69,7 @@ class Renderer * @param string $template * @param array $vars * @return string - * @throws InternalServerErrorException + * @throws ServiceUnavailableException */ public static function replaceMacros(string $template, array $vars = []) { @@ -87,7 +87,7 @@ class Renderer $message = is_site_admin() ? $e->getMessage() : DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.'); - throw new InternalServerErrorException($message); + throw new ServiceUnavailableException($message); } DI::profiler()->stopRecording(); @@ -102,7 +102,7 @@ class Renderer * @param string $subDir Subdirectory (Optional) * * @return string template. - * @throws InternalServerErrorException + * @throws ServiceUnavailableException */ public static function getMarkupTemplate($file, $subDir = '') { @@ -116,7 +116,7 @@ class Renderer $message = is_site_admin() ? $e->getMessage() : DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.'); - throw new InternalServerErrorException($message); + throw new ServiceUnavailableException($message); } DI::profiler()->stopRecording(); @@ -128,7 +128,7 @@ class Renderer * Register template engine class * * @param string $class - * @throws InternalServerErrorException + * @throws ServiceUnavailableException */ public static function registerTemplateEngine($class) { @@ -143,7 +143,7 @@ class Renderer $message = is_site_admin() ? $admin_message : DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.'); - throw new InternalServerErrorException($message); + throw new ServiceUnavailableException($message); } } @@ -154,7 +154,7 @@ class Renderer * or default * * @return TemplateEngine Template Engine instance - * @throws InternalServerErrorException + * @throws ServiceUnavailableException */ public static function getTemplateEngine() { @@ -177,7 +177,7 @@ class Renderer $message = is_site_admin() ? $admin_message : DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.'); - throw new InternalServerErrorException($message); + throw new ServiceUnavailableException($message); } /** diff --git a/src/Core/System.php b/src/Core/System.php index c61225e48..15f4ba60a 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -22,7 +22,10 @@ namespace Friendica\Core; use Friendica\DI; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\BadRequestException; +use Friendica\Network\HTTPException\FoundException; +use Friendica\Network\HTTPException\MovedPermanentlyException; +use Friendica\Network\HTTPException\TemporaryRedirectException; use Friendica\Util\XML; /** @@ -122,7 +125,9 @@ class System */ public static function httpExit($val, $message = '', $content = '') { - Logger::log('http_status_exit ' . $val); + if ($val >= 400) { + Logger::debug('Exit with error', ['code' => $val, 'message' => $message, 'callstack' => System::callstack(20), 'method' => $_SERVER['REQUEST_METHOD'], 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']); + } header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $message); echo $content; @@ -132,6 +137,9 @@ class System public static function jsonError($httpCode, $data, $content_type = 'application/json') { + if ($httpCode >= 400) { + Logger::debug('Exit with error', ['code' => $httpCode, 'content_type' => $content_type, 'callstack' => System::callstack(20), 'method' => $_SERVER['REQUEST_METHOD'], 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']); + } header($_SERVER["SERVER_PROTOCOL"] . ' ' . $httpCode); self::jsonExit($data, $content_type); } @@ -222,28 +230,25 @@ class System * @param string $url The new Location to redirect * @param int $code The redirection code, which is used (Default is 302) * - * @throws InternalServerErrorException If the URL is not fully qualified + * @throws BadRequestException If the URL is not fully qualified */ public static function externalRedirect($url, $code = 302) { if (empty(parse_url($url, PHP_URL_SCHEME))) { - throw new InternalServerErrorException("'$url' is not a fully qualified URL, please use App->internalRedirect() instead"); - } - - switch ($code) { - case 302: - // this is the default code for a REDIRECT - // We don't need a extra header here - break; - case 301: - header('HTTP/1.1 301 Moved Permanently'); - break; - case 307: - header('HTTP/1.1 307 Temporary Redirect'); - break; + throw new BadRequestException("'$url' is not a fully qualified URL, please use App->internalRedirect() instead"); } header("Location: $url"); + + switch ($code) { + case 302: + throw new FoundException(); + case 301: + throw new MovedPermanentlyException(); + case 307: + throw new TemporaryRedirectException(); + } + exit(); } diff --git a/src/Database/Database.php b/src/Database/Database.php index a654cccc5..88363cc39 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -23,7 +23,7 @@ namespace Friendica\Database; use Friendica\Core\Config\Cache; use Friendica\Core\System; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\ServiceUnavailableException; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; use mysqli; @@ -520,7 +520,7 @@ class Database $called_from_e = ($called_from['function'] == 'e'); if (!isset($this->connection)) { - throw new InternalServerErrorException('The Connection is empty, although connected is set true.'); + throw new ServiceUnavailableException('The Connection is empty, although connected is set true.'); } switch ($this->driver) { diff --git a/src/Factory/Api/Mastodon/Application.php b/src/Factory/Api/Mastodon/Application.php index f0567f2eb..a7c0e6fc6 100644 --- a/src/Factory/Api/Mastodon/Application.php +++ b/src/Factory/Api/Mastodon/Application.php @@ -23,7 +23,7 @@ namespace Friendica\Factory\Api\Mastodon; use Friendica\BaseFactory; use Friendica\Database\Database; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\UnprocessableEntityException; use Psr\Log\LoggerInterface; class Application extends BaseFactory @@ -42,13 +42,13 @@ class Application extends BaseFactory * * @return \Friendica\Object\Api\Mastodon\Application * - * @throws InternalServerErrorException + * @throws UnprocessableEntityException */ public function createFromApplicationId(int $id): \Friendica\Object\Api\Mastodon\Application { $application = $this->dba->selectFirst('application', ['client_id', 'client_secret', 'id', 'name', 'redirect_uri', 'website'], ['id' => $id]); if (!$this->dba->isResult($application)) { - throw new InternalServerErrorException(sprintf("ID '%s' not found", $id)); + throw new UnprocessableEntityException(sprintf("ID '%s' not found", $id)); } return new \Friendica\Object\Api\Mastodon\Application( diff --git a/src/Module/Admin/Summary.php b/src/Module/Admin/Summary.php index 2d081f407..730cf3719 100644 --- a/src/Module/Admin/Summary.php +++ b/src/Module/Admin/Summary.php @@ -32,8 +32,7 @@ use Friendica\DI; use Friendica\Factory\ConfigFactory; use Friendica\Model\Register; use Friendica\Module\BaseAdmin; -use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Util\ConfigFileLoader; +use Friendica\Network\HTTPException\ServiceUnavailableException; use Friendica\Util\DateTimeFormat; class Summary extends BaseAdmin @@ -129,7 +128,7 @@ class Summary extends BaseAdmin $stream = $fileSystem->createStream($file); if (!isset($stream)) { - throw new InternalServerErrorException('Stream is null.'); + throw new ServiceUnavailableException('Stream is null.'); } } catch (\Throwable $exception) { @@ -143,7 +142,7 @@ class Summary extends BaseAdmin $stream = $fileSystem->createStream($file); if (!isset($stream)) { - throw new InternalServerErrorException('Stream is null.'); + throw new ServiceUnavailableException('Stream is null.'); } } } catch (\Throwable $exception) { diff --git a/src/Module/Diaspora/Receive.php b/src/Module/Diaspora/Receive.php index 0860dfd67..dc6fb716b 100644 --- a/src/Module/Diaspora/Receive.php +++ b/src/Module/Diaspora/Receive.php @@ -96,7 +96,9 @@ class Receive extends BaseModule if (Diaspora::dispatch($importer, $msg)) { throw new HTTPException\OKException(); } else { - throw new HTTPException\InternalServerErrorException(); + // We couldn't process the content. + // To avoid the remote system trying again we send the message that we accepted the content. + throw new HTTPException\AcceptedException(); } } diff --git a/src/Module/Friendica.php b/src/Module/Friendica.php index 95a319a41..08e463bd4 100644 --- a/src/Module/Friendica.php +++ b/src/Module/Friendica.php @@ -30,6 +30,7 @@ use Friendica\Database\PostUpdate; use Friendica\DI; use Friendica\Model\User; use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\ImATeapotException; use Friendica\Protocol\ActivityPub; /** diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 0b03f4a79..58a2eeac5 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -33,6 +33,7 @@ use Friendica\Model\Storage\ExternalResource; use Friendica\Model\Storage\SystemResource; use Friendica\Model\User; use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\NotModifiedException; use Friendica\Object\Image; use Friendica\Util\Images; use Friendica\Util\Network; @@ -55,7 +56,6 @@ class Photo extends BaseModule $totalstamp = microtime(true); if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { - header("HTTP/1.1 304 Not Modified"); header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) { header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]); @@ -67,7 +67,7 @@ class Photo extends BaseModule header_remove("Expires"); header_remove("Cache-Control"); } - exit; + throw new NotModifiedException(); } Profile::addVisitorCookieForHTTPSigner(); diff --git a/src/Module/Proxy.php b/src/Module/Proxy.php index 15ef1c441..86b8a95cb 100644 --- a/src/Module/Proxy.php +++ b/src/Module/Proxy.php @@ -25,6 +25,7 @@ use Friendica\BaseModule; use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\DI; +use Friendica\Network\HTTPException\NotModifiedException; use Friendica\Object\Image; use Friendica\Util\HTTPSignature; use Friendica\Util\Images; @@ -53,7 +54,6 @@ class Proxy extends BaseModule } if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { - header("HTTP/1.1 304 Not Modified"); header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) { header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]); @@ -65,7 +65,7 @@ class Proxy extends BaseModule header_remove("Expires"); header_remove("Cache-Control"); } - exit; + throw new NotModifiedException(); } if (empty($request['url'])) { diff --git a/src/Module/Special/HTTPException.php b/src/Module/Special/HTTPException.php index 09e962407..137b72b36 100644 --- a/src/Module/Special/HTTPException.php +++ b/src/Module/Special/HTTPException.php @@ -21,6 +21,7 @@ namespace Friendica\Module\Special; +use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\DI; @@ -42,36 +43,10 @@ class HTTPException */ private static function getVars(\Friendica\Network\HTTPException $e) { - $message = $e->getMessage(); - - $titles = [ - 200 => 'OK', - 400 => DI::l10n()->t('Bad Request'), - 401 => DI::l10n()->t('Unauthorized'), - 403 => DI::l10n()->t('Forbidden'), - 404 => DI::l10n()->t('Not Found'), - 500 => DI::l10n()->t('Internal Server Error'), - 503 => DI::l10n()->t('Service Unavailable'), - ]; - $title = ($titles[$e->getCode()] ?? '') ?: 'Error ' . $e->getCode(); - - if (empty($message)) { - // Explanations are taken from https://en.wikipedia.org/wiki/List_of_HTTP_status_codes - $explanation = [ - 400 => DI::l10n()->t('The server cannot or will not process the request due to an apparent client error.'), - 401 => DI::l10n()->t('Authentication is required and has failed or has not yet been provided.'), - 403 => DI::l10n()->t('The request was valid, but the server is refusing action. The user might not have the necessary permissions for a resource, or may need an account.'), - 404 => DI::l10n()->t('The requested resource could not be found but may be available in the future.'), - 500 => DI::l10n()->t('An unexpected condition was encountered and no more specific message is suitable.'), - 503 => DI::l10n()->t('The server is currently unavailable (because it is overloaded or down for maintenance). Please try again later.'), - ]; - - $message = $explanation[$e->getCode()] ?? ''; - } - + // Explanations are mostly taken from https://en.wikipedia.org/wiki/List_of_HTTP_status_codes $vars = [ - '$title' => $title, - '$message' => $message, + '$title' => $e->httpdesc ?: 'Error ' . $e->getCode(), + '$message' => $e->getMessage() ?: $e->explanation, '$back' => DI::l10n()->t('Go back'), '$stack_trace' => DI::l10n()->t('Stack trace:'), ]; @@ -113,6 +88,10 @@ class HTTPException { header($_SERVER["SERVER_PROTOCOL"] . ' ' . $e->getCode() . ' ' . $e->httpdesc); + if ($e->getCode() >= 400) { + Logger::debug('Exit with error', ['code' => $e->getCode(), 'description' => $e->httpdesc, 'query' => DI::args()->getQueryString(), 'callstack' => System::callstack(20), 'method' => $_SERVER['REQUEST_METHOD'], 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']); + } + $tpl = Renderer::getMarkupTemplate('exception.tpl'); return Renderer::replaceMacros($tpl, self::getVars($e)); diff --git a/src/Network/CurlResult.php b/src/Network/CurlResult.php index 8b3b12876..232643786 100644 --- a/src/Network/CurlResult.php +++ b/src/Network/CurlResult.php @@ -22,8 +22,7 @@ namespace Friendica\Network; use Friendica\Core\Logger; -use Friendica\Core\System; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\UnprocessableEntityException; use Friendica\Util\Network; /** @@ -102,7 +101,7 @@ class CurlResult implements IHTTPResult * @param string $url optional URL * * @return IHTTPResult a CURL with error response - * @throws InternalServerErrorException + * @throws UnprocessableEntityException */ public static function createErrorCurl($url = '') { @@ -117,12 +116,12 @@ class CurlResult implements IHTTPResult * @param int $errorNumber the error number or 0 (zero) if no error * @param string $error the error message or '' (the empty string) if no * - * @throws InternalServerErrorException when HTTP code of the CURL response is missing + * @throws UnprocessableEntityException when HTTP code of the CURL response is missing */ public function __construct($url, $result, $info, $errorNumber = 0, $error = '') { if (!array_key_exists('http_code', $info)) { - throw new InternalServerErrorException('CURL response doesn\'t contains a response HTTP code'); + throw new UnprocessableEntityException('CURL response doesn\'t contains a response HTTP code'); } $this->returnCode = $info['http_code']; diff --git a/src/Network/HTTPException.php b/src/Network/HTTPException.php index d6698605d..1ca6bd36d 100644 --- a/src/Network/HTTPException.php +++ b/src/Network/HTTPException.php @@ -31,15 +31,11 @@ use Exception; */ abstract class HTTPException extends Exception { - public $httpdesc = ''; + public $httpdesc = ''; + public $explanation = ''; public function __construct($message = '', Exception $previous = null) { parent::__construct($message, $this->code, $previous); - - if (empty($this->httpdesc)) { - $classname = str_replace('Exception', '', str_replace('Friendica\Network\HTTPException\\', '', get_class($this))); - $this->httpdesc = preg_replace("|([a-z])([A-Z])|",'$1 $2', $classname); - } } } diff --git a/src/Network/HTTPException/AcceptedException.php b/src/Network/HTTPException/AcceptedException.php index a52c1a3ea..e7a8e5a3e 100644 --- a/src/Network/HTTPException/AcceptedException.php +++ b/src/Network/HTTPException/AcceptedException.php @@ -26,4 +26,5 @@ use Friendica\Network\HTTPException; class AcceptedException extends HTTPException { protected $code = 202; + var $httpdesc = 'Accepted'; } diff --git a/src/Network/HTTPException/BadGatewayException.php b/src/Network/HTTPException/BadGatewayException.php index ceaa3189e..d2f6c3fbe 100644 --- a/src/Network/HTTPException/BadGatewayException.php +++ b/src/Network/HTTPException/BadGatewayException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class BadGatewayException extends HTTPException { - protected $code = 502; + protected $code = 502; + var $httpdesc = 'Bad Gateway'; + var $explanation = 'The server was acting as a gateway or proxy and received an invalid response from the upstream server.'; } diff --git a/src/Network/HTTPException/BadRequestException.php b/src/Network/HTTPException/BadRequestException.php index 5b71e5b97..c2fe816af 100644 --- a/src/Network/HTTPException/BadRequestException.php +++ b/src/Network/HTTPException/BadRequestException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class BadRequestException extends HTTPException { - protected $code = 400; + protected $code = 400; + var $httpdesc = 'Bad Request'; + var $explanation = 'The server cannot or will not process the request due to an apparent client error.'; } diff --git a/src/Network/HTTPException/ConflictException.php b/src/Network/HTTPException/ConflictException.php index f7e267835..01cfc8dce 100644 --- a/src/Network/HTTPException/ConflictException.php +++ b/src/Network/HTTPException/ConflictException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class ConflictException extends HTTPException { - protected $code = 409; + protected $code = 409; + var $httpdesc = 'Conflict '; + var $explanation = 'Indicates that the request could not be processed because of conflict in the current state of the resource, such as an edit conflict between multiple simultaneous updates.'; } diff --git a/src/Network/HTTPException/ExpectationFailedException.php b/src/Network/HTTPException/ExpectationFailedException.php index 4269fbde5..9ae58bcc8 100644 --- a/src/Network/HTTPException/ExpectationFailedException.php +++ b/src/Network/HTTPException/ExpectationFailedException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class ExpectationFailedException extends HTTPException { - protected $code = 417; + protected $code = 417; + var $httpdesc = 'Expectation Failed'; + var $explanation = 'The server cannot meet the requirements of the Expect request-header field.'; } diff --git a/src/Network/HTTPException/ForbiddenException.php b/src/Network/HTTPException/ForbiddenException.php index c492cb928..a1dafa9a5 100644 --- a/src/Network/HTTPException/ForbiddenException.php +++ b/src/Network/HTTPException/ForbiddenException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class ForbiddenException extends HTTPException { - protected $code = 403; + protected $code = 403; + var $httpdesc = 'Forbidden'; + var $explanation = 'The request was valid, but the server is refusing action. The user might not have the necessary permissions for a resource, or may need an account.'; } diff --git a/src/Network/HTTPException/FoundException.php b/src/Network/HTTPException/FoundException.php new file mode 100644 index 000000000..c60a5f8c8 --- /dev/null +++ b/src/Network/HTTPException/FoundException.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\Network\HTTPException; + +use Friendica\Network\HTTPException; + +class FoundException extends HTTPException +{ + protected $code = 302; + var $httpdesc = 'Found (Moved Temporarily)'; +} diff --git a/src/Network/HTTPException/GatewayTimeoutException.php b/src/Network/HTTPException/GatewayTimeoutException.php index 4aca8fd83..2f674b2dc 100644 --- a/src/Network/HTTPException/GatewayTimeoutException.php +++ b/src/Network/HTTPException/GatewayTimeoutException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class GatewayTimeoutException extends HTTPException { - protected $code = 504; + protected $code = 504; + var $httpdesc = 'Gateway Timeout'; + var $explanation = 'The server was acting as a gateway or proxy and did not receive a timely response from the upstream server.'; } diff --git a/src/Network/HTTPException/GoneException.php b/src/Network/HTTPException/GoneException.php index 77f0a5f7a..73eedcb67 100644 --- a/src/Network/HTTPException/GoneException.php +++ b/src/Network/HTTPException/GoneException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class GoneException extends HTTPException { - protected $code = 410; + protected $code = 410; + var $httpdesc = 'Gone'; + var $explanation = 'Indicates that the resource requested is no longer available and will not be available again.'; } diff --git a/src/Network/HTTPException/ImATeapotException.php b/src/Network/HTTPException/ImATeapotException.php index 689bc36a2..dcfd72de0 100644 --- a/src/Network/HTTPException/ImATeapotException.php +++ b/src/Network/HTTPException/ImATeapotException.php @@ -25,6 +25,7 @@ use Friendica\Network\HTTPException; class ImATeapotException extends HTTPException { - protected $code = 418; - var $httpdesc = "I'm A Teapot"; + protected $code = 418; + var $httpdesc = "I'm A Teapot"; + var $explanation = 'This is a teapot that is requested to brew coffee.'; } diff --git a/src/Network/HTTPException/InternalServerErrorException.php b/src/Network/HTTPException/InternalServerErrorException.php index 570f8e0fc..d5df8fdd3 100644 --- a/src/Network/HTTPException/InternalServerErrorException.php +++ b/src/Network/HTTPException/InternalServerErrorException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class InternalServerErrorException extends HTTPException { - protected $code = 500; + protected $code = 500; + var $httpdesc = 'Internal Server Error'; + var $explanation = 'An unexpected condition was encountered and no more specific message is suitable.'; } diff --git a/src/Network/HTTPException/LenghtRequiredException.php b/src/Network/HTTPException/LenghtRequiredException.php index 307154712..3818f681a 100644 --- a/src/Network/HTTPException/LenghtRequiredException.php +++ b/src/Network/HTTPException/LenghtRequiredException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class LenghtRequiredException extends HTTPException { - protected $code = 411; + protected $code = 411; + var $httpdesc = 'Length Required'; + var $explanation = 'The request did not specify the length of its content, which is required by the requested resource.'; } diff --git a/src/Network/HTTPException/MethodNotAllowedException.php b/src/Network/HTTPException/MethodNotAllowedException.php index 6a733a374..d09c0fe31 100644 --- a/src/Network/HTTPException/MethodNotAllowedException.php +++ b/src/Network/HTTPException/MethodNotAllowedException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class MethodNotAllowedException extends HTTPException { - protected $code = 405; + protected $code = 405; + var $httpdesc = 'Method Not Allowed'; + var $explanation = 'A request method is not supported for the requested resource; for example, a GET request on a form that requires data to be presented via POST, or a PUT request on a read-only resource.'; } diff --git a/src/Network/HTTPException/MovedPermanently.php b/src/Network/HTTPException/MovedPermanently.php new file mode 100644 index 000000000..ef78f87bd --- /dev/null +++ b/src/Network/HTTPException/MovedPermanently.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\Network\HTTPException; + +use Friendica\Network\HTTPException; + +class MovedPermanentlyException extends HTTPException +{ + protected $code = 301; + var $httpdesc = 'Moved Permanently'; +} diff --git a/src/Network/HTTPException/NoContentException.php b/src/Network/HTTPException/NoContentException.php index 78900aff5..90d9d2ae6 100644 --- a/src/Network/HTTPException/NoContentException.php +++ b/src/Network/HTTPException/NoContentException.php @@ -26,4 +26,5 @@ use Friendica\Network\HTTPException; class NoContentException extends HTTPException { protected $code = 204; + var $httpdesc = 'No Content'; } diff --git a/src/Network/HTTPException/NonAcceptableException.php b/src/Network/HTTPException/NonAcceptableException.php index 1eddc8b28..c9811ddb7 100644 --- a/src/Network/HTTPException/NonAcceptableException.php +++ b/src/Network/HTTPException/NonAcceptableException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class NonAcceptableException extends HTTPException { - protected $code = 406; + protected $code = 406; + var $httpdesc = 'Not Acceptable'; + var $explanation = 'The requested resource is capable of generating only content not acceptable according to the Accept headers sent in the request.'; } diff --git a/src/Network/HTTPException/NotFoundException.php b/src/Network/HTTPException/NotFoundException.php index a89d8a4e1..9acc32031 100644 --- a/src/Network/HTTPException/NotFoundException.php +++ b/src/Network/HTTPException/NotFoundException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class NotFoundException extends HTTPException { - protected $code = 404; + protected $code = 404; + var $httpdesc = 'Not Found'; + var $explanation = 'The requested resource could not be found but may be available in the future.'; } diff --git a/src/Network/HTTPException/NotImplementedException.php b/src/Network/HTTPException/NotImplementedException.php index 3a84f6a54..6c2d1e25e 100644 --- a/src/Network/HTTPException/NotImplementedException.php +++ b/src/Network/HTTPException/NotImplementedException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class NotImplementedException extends HTTPException { - protected $code = 501; + protected $code = 501; + var $httpdesc = 'Not Implemented'; + var $explanation = 'The server either does not recognize the request method, or it lacks the ability to fulfil the request. Usually this implies future availability (e.g., a new feature of a web-service API).'; } diff --git a/src/Network/HTTPException/NotModifiedException.php b/src/Network/HTTPException/NotModifiedException.php new file mode 100644 index 000000000..431b2096a --- /dev/null +++ b/src/Network/HTTPException/NotModifiedException.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\Network\HTTPException; + +use Friendica\Network\HTTPException; + +class NotModifiedException extends HTTPException +{ + protected $code = 304; + var $httpdesc = 'Not Modified'; +} diff --git a/src/Network/HTTPException/OKException.php b/src/Network/HTTPException/OKException.php index 44dc6c80b..e4b409ce0 100644 --- a/src/Network/HTTPException/OKException.php +++ b/src/Network/HTTPException/OKException.php @@ -26,4 +26,5 @@ use Friendica\Network\HTTPException; class OKException extends HTTPException { protected $code = 200; + var $httpdesc = 'OK'; } diff --git a/src/Network/HTTPException/PreconditionFailedException.php b/src/Network/HTTPException/PreconditionFailedException.php index 9baf5a092..fe4ebcb12 100644 --- a/src/Network/HTTPException/PreconditionFailedException.php +++ b/src/Network/HTTPException/PreconditionFailedException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class PreconditionFailedException extends HTTPException { - protected $code = 412; + protected $code = 412; + var $httpdesc = 'Precondition Failed'; + var $explanation = 'The server does not meet one of the preconditions that the requester put on the request header fields.'; } diff --git a/src/Network/HTTPException/ServiceUnavailableException.php b/src/Network/HTTPException/ServiceUnavailableException.php index 2f9ef8863..a88390e6a 100644 --- a/src/Network/HTTPException/ServiceUnavailableException.php +++ b/src/Network/HTTPException/ServiceUnavailableException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class ServiceUnavailableException extends HTTPException { - protected $code = 503; + protected $code = 503; + var $httpdesc = 'Service Unavailable'; + var $explanation = 'The server is currently unavailable (because it is overloaded or down for maintenance). Please try again later.'; } diff --git a/src/Network/HTTPException/TemporaryRedirectException.php b/src/Network/HTTPException/TemporaryRedirectException.php new file mode 100644 index 000000000..cae4be728 --- /dev/null +++ b/src/Network/HTTPException/TemporaryRedirectException.php @@ -0,0 +1,30 @@ +. + * + */ + +namespace Friendica\Network\HTTPException; + +use Friendica\Network\HTTPException; + +class TemporaryRedirectException extends HTTPException +{ + protected $code = 307; + var $httpdesc = 'Temporary Redirect'; +} diff --git a/src/Network/HTTPException/TooManyRequestsException.php b/src/Network/HTTPException/TooManyRequestsException.php index 567191fc5..c94679af7 100644 --- a/src/Network/HTTPException/TooManyRequestsException.php +++ b/src/Network/HTTPException/TooManyRequestsException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class TooManyRequestsException extends HTTPException { - protected $code = 429; + protected $code = 429; + var $httpdesc = 'Too Many Requests'; + var $explanation = 'The user has sent too many requests in a given amount of time.'; } diff --git a/src/Network/HTTPException/UnauthorizedException.php b/src/Network/HTTPException/UnauthorizedException.php index d7bcb5c74..ad6adfd42 100644 --- a/src/Network/HTTPException/UnauthorizedException.php +++ b/src/Network/HTTPException/UnauthorizedException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class UnauthorizedException extends HTTPException { - protected $code = 401; + protected $code = 401; + var $httpdesc = 'Unauthorized'; + var $explanation = 'Authentication is required and has failed or has not yet been provided.'; } diff --git a/src/Network/HTTPException/UnprocessableEntityException.php b/src/Network/HTTPException/UnprocessableEntityException.php index 41f952941..29b0d3158 100644 --- a/src/Network/HTTPException/UnprocessableEntityException.php +++ b/src/Network/HTTPException/UnprocessableEntityException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class UnprocessableEntityException extends HTTPException { - protected $code = 422; + protected $code = 422; + var $httpdesc = 'Unprocessable Entity'; + var $explanation = 'The request was well-formed but was unable to be followed due to semantic errors.'; } diff --git a/src/Network/HTTPException/UnsupportedMediaTypeException.php b/src/Network/HTTPException/UnsupportedMediaTypeException.php index 00c89cebd..adf008d01 100644 --- a/src/Network/HTTPException/UnsupportedMediaTypeException.php +++ b/src/Network/HTTPException/UnsupportedMediaTypeException.php @@ -25,5 +25,7 @@ use Friendica\Network\HTTPException; class UnsupportedMediaTypeException extends HTTPException { - protected $code = 415; + protected $code = 415; + var $httpdesc = 'Unsupported Media Type'; + var $explanation = 'The request entity has a media type which the server or resource does not support. For example, the client uploads an image as image/svg+xml, but the server requires that images use a different format.'; } diff --git a/src/Render/FriendicaSmartyEngine.php b/src/Render/FriendicaSmartyEngine.php index 8eafd7d94..c336273c7 100644 --- a/src/Render/FriendicaSmartyEngine.php +++ b/src/Render/FriendicaSmartyEngine.php @@ -23,7 +23,7 @@ namespace Friendica\Render; use Friendica\Core\Hook; use Friendica\DI; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\ServiceUnavailableException; use Friendica\Util\Strings; /** @@ -54,7 +54,7 @@ final class FriendicaSmartyEngine extends TemplateEngine $message = is_site_admin() ? $admin_message : DI::l10n()->t('Friendica can\'t display this page at the moment, please contact the administrator.'); - throw new InternalServerErrorException($message); + throw new ServiceUnavailableException($message); } } diff --git a/src/Util/EMailer/MailBuilder.php b/src/Util/EMailer/MailBuilder.php index 56034a696..1e1a06491 100644 --- a/src/Util/EMailer/MailBuilder.php +++ b/src/Util/EMailer/MailBuilder.php @@ -27,7 +27,7 @@ use Friendica\Core\Config\IConfig; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Model\User; -use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\UnprocessableEntityException; use Friendica\Object\Email; use Friendica\Object\EMail\IEmail; use Psr\Log\LoggerInterface; @@ -226,7 +226,7 @@ abstract class MailBuilder * * @return IEmail A new generated email * - * @throws InternalServerErrorException + * @throws UnprocessableEntityException * @throws Exception */ public function build(bool $raw = false) @@ -241,11 +241,11 @@ abstract class MailBuilder } if (empty($this->recipientAddress)) { - throw new InternalServerErrorException('Recipient address is missing.'); + throw new UnprocessableEntityException('Recipient address is missing.'); } if (empty($this->senderAddress) || empty($this->senderName)) { - throw new InternalServerErrorException('Sender address or name is missing.'); + throw new UnprocessableEntityException('Sender address or name is missing.'); } $this->senderNoReply = $this->senderNoReply ?? $this->senderAddress; diff --git a/src/Util/HTTPSignature.php b/src/Util/HTTPSignature.php index f11dbcceb..663c5a752 100644 --- a/src/Util/HTTPSignature.php +++ b/src/Util/HTTPSignature.php @@ -476,7 +476,7 @@ class HTTPSignature public static function getSigner($content, $http_headers) { if (empty($http_headers['HTTP_SIGNATURE'])) { - Logger::info('No HTTP_SIGNATURE header'); + Logger::debug('No HTTP_SIGNATURE header'); return false; } diff --git a/src/Util/Network.php b/src/Util/Network.php index 9c7b6a8af..2631fc75b 100644 --- a/src/Util/Network.php +++ b/src/Util/Network.php @@ -25,6 +25,7 @@ use Friendica\Core\Hook; use Friendica\Core\Logger; use Friendica\DI; use Friendica\Model\Contact; +use Friendica\Network\HTTPException\NotModifiedException; class Network { @@ -544,8 +545,7 @@ class Network header('Last-Modified: ' . $last_modified); if ($flag_not_modified) { - header("HTTP/1.1 304 Not Modified"); - exit; + throw new NotModifiedException(); } } diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 16baea281..6d7a7050b 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -693,7 +693,7 @@ class Notifier private static function notifySelfRemoval($self_user_id, $priority, $created) { $owner = User::getOwnerDataById($self_user_id); - if (!$owner) { + if (empty($self_user_id) || empty($owner)) { return false; } diff --git a/view/theme/frio/style.php b/view/theme/frio/style.php index c60fb7a8f..f68f4c291 100644 --- a/view/theme/frio/style.php +++ b/view/theme/frio/style.php @@ -20,6 +20,7 @@ */ use Friendica\DI; +use Friendica\Network\HTTPException\NotModifiedException; use Friendica\Util\Strings; require_once 'view/theme/frio/theme.php'; @@ -225,8 +226,7 @@ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && isset($_SERVER['HTTP_IF_NONE_MA stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])); if (($cached_modified == $modified) && ($cached_etag == $etag)) { - header('HTTP/1.1 304 Not Modified'); - exit(); + throw new NotModifiedException(); } } diff --git a/view/theme/vier/style.php b/view/theme/vier/style.php index a1b492b95..909a27fc6 100644 --- a/view/theme/vier/style.php +++ b/view/theme/vier/style.php @@ -21,6 +21,7 @@ use Friendica\Core\Logger; use Friendica\DI; +use Friendica\Network\HTTPException\NotModifiedException; $uid = $_REQUEST['puid'] ?? 0; @@ -67,8 +68,7 @@ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && isset($_SERVER['HTTP_IF_NONE_MA stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])); if (($cached_modified == $modified) && ($cached_etag == $etag)) { - header('HTTP/1.1 304 Not Modified'); - exit(); + throw new NotModifiedException(); } } echo $stylecss;