diff --git a/lib/REST.php b/lib/REST.php index f7818e5..56dbf11 100644 --- a/lib/REST.php +++ b/lib/REST.php @@ -7,11 +7,11 @@ declare(strict_types=1); namespace JKingWeb\Arsse; use JKingWeb\Arsse\Misc\URL; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\ServerRequestFactory; -use Laminas\Diactoros\Response\EmptyResponse; class REST { public const API_LIST = [ @@ -101,7 +101,7 @@ class REST { $res = $drv->dispatch($req); } } catch (REST\Exception501 $e) { - $res = new EmptyResponse(501); + $res = HTTP::respEmpty(501); } // modify the response so that it has all the required metadata return $this->normalizeResponse($res, $req); @@ -180,7 +180,7 @@ class REST { } // if the response is to a HEAD request, the body should be omitted if ($req && $req->getMethod() === "HEAD") { - $res = new EmptyResponse($res->getStatusCode(), $res->getHeaders()); + $res = HTTP::respEmpty($res->getStatusCode(), $res->getHeaders()); } // if an Allow header field is present, normalize it if ($res->hasHeader("Allow")) { diff --git a/lib/REST/Fever/API.php b/lib/REST/Fever/API.php index 7ad69ba..72f3e9b 100644 --- a/lib/REST/Fever/API.php +++ b/lib/REST/Fever/API.php @@ -10,13 +10,12 @@ use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Misc\ValueInfo as V; use JKingWeb\Arsse\Misc\Date; -use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Misc\HTTP; +use JKingWeb\Arsse\Db\ExceptionInput; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; -use Laminas\Diactoros\Response\EmptyResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { public const LEVEL = 3; @@ -62,11 +61,11 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { $P = $this->normalizeInputPost($req->getParsedBody() ?? []); if (!isset($G['api'])) { // the original would have shown the Fever UI in the absence of the "api" parameter, but we'll return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } switch ($req->getMethod()) { case "OPTIONS": - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => implode(", ", self::ACCEPTED_TYPES), ]); @@ -82,7 +81,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { $out['auth'] = 1; } elseif (Arsse::$conf->userHTTPAuthRequired || Arsse::$conf->userPreAuth || $req->getAttribute("authenticationFailed", false)) { // otherwise if HTTP authentication failed or is required, deny access at the HTTP level - return new EmptyResponse(401); + return HTTP::respEmpty(401); } // produce a full response if authenticated or a basic response otherwise if ($this->logIn(strtolower($P['api_key'] ?? ""))) { @@ -93,7 +92,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { // return the result, possibly formatted as XML return $this->formatResponse($out, ($G['api'] === "xml")); default: - return new EmptyResponse(405, ['Allow' => "OPTIONS,POST"]); + return HTTP::respEmpty(405, ['Allow' => "OPTIONS,POST"]); } } diff --git a/lib/REST/Miniflux/Status.php b/lib/REST/Miniflux/Status.php index 367a7a6..c829193 100644 --- a/lib/REST/Miniflux/Status.php +++ b/lib/REST/Miniflux/Status.php @@ -6,9 +6,9 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST\Miniflux; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\TextResponse; class Status extends \JKingWeb\Arsse\REST\AbstractHandler { @@ -18,13 +18,13 @@ class Status extends \JKingWeb\Arsse\REST\AbstractHandler { public function dispatch(ServerRequestInterface $req): ResponseInterface { $target = parse_url($req->getRequestTarget())['path'] ?? ""; if (!in_array($target, ["/version", "/healthcheck"])) { - return new EmptyResponse(404); + return HTTP::respEmpty(404); } $method = $req->getMethod(); if ($method === "OPTIONS") { - return new EmptyResponse(204, ['Allow' => "HEAD, GET"]); + return HTTP::respEmpty(204, ['Allow' => "HEAD, GET"]); } elseif ($method !== "GET") { - return new EmptyResponse(405, ['Allow' => "HEAD, GET"]); + return HTTP::respEmpty(405, ['Allow' => "HEAD, GET"]); } $out = ""; if ($target === "/version") { diff --git a/lib/REST/Miniflux/V1.php b/lib/REST/Miniflux/V1.php index 6897472..4ed828a 100644 --- a/lib/REST/Miniflux/V1.php +++ b/lib/REST/Miniflux/V1.php @@ -19,6 +19,7 @@ use JKingWeb\Arsse\ImportExport\OPML; use JKingWeb\Arsse\ImportExport\Exception as ImportException; use JKingWeb\Arsse\Misc\Date; use JKingWeb\Arsse\Misc\URL; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\ValueInfo as V; use JKingWeb\Arsse\REST\Exception; use JKingWeb\Arsse\Rule\Rule; @@ -26,7 +27,6 @@ use JKingWeb\Arsse\User\ExceptionConflict; use JKingWeb\Arsse\User\Exception as UserException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\TextResponse as GenericResponse; use Laminas\Diactoros\Uri; @@ -295,10 +295,10 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { // @codeCoverageIgnoreStart } catch (Exception $e) { // if there was a REST exception return 400 - return new EmptyResponse(400); + return HTTP::respEmpty(400); } catch (AbstractException $e) { // if there was any other Arsse exception return 500 - return new EmptyResponse(500); + return HTTP::respEmpty(500); } // @codeCoverageIgnoreEnd } @@ -317,11 +317,11 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { return self::CALLS[$url][$method]; } else { // otherwise return 405 - return new EmptyResponse(405, ['Allow' => implode(", ", array_keys(self::CALLS[$url]))]); + return HTTP::respEmpty(405, ['Allow' => implode(", ", array_keys(self::CALLS[$url]))]); } } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -451,13 +451,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { if (in_array("GET", $allowed)) { array_unshift($allowed, "HEAD"); } - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => implode(", ", $allowed), 'Accept' => implode(", ", $url === "/import" ? self::ACCEPTED_TYPES_OPML : self::ACCEPTED_TYPES_JSON), ]); } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -637,7 +637,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionConflict $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } /** Returns a useful subset of user metadata @@ -728,7 +728,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function transformFeed(array $sub, int $uid, string $rootName, \DateTimeZone $tz): array { @@ -866,7 +866,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function deleteFeed(array $path): ResponseInterface { try { Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $path[1]); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } @@ -1104,7 +1104,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } assert(isset($in), new \Exception("Unknown status specified")); Arsse::$db->articleMark(Arsse::$user->id, $in, (new Context)->articles($data['entry_ids'])); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function massRead(Context $c): void { @@ -1118,7 +1118,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { return new ErrorResponse("403", 403); } $this->massRead(new Context); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function markFeed(array $path): ResponseInterface { @@ -1127,7 +1127,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function markCategory(array $path): ResponseInterface { @@ -1144,7 +1144,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function toggleEntryBookmark(array $path): ResponseInterface { @@ -1162,7 +1162,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function refreshFeed(array $path): ResponseInterface { @@ -1172,13 +1172,13 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { return new ErrorResponse("404", 404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function refreshAllFeeds(): ResponseInterface { // NOTE: This is a no-op // It could be implemented, but the need is considered low since we use a dynamic schedule always - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function opmlImport(string $data): ResponseInterface { diff --git a/lib/REST/NextcloudNews/V1_2.php b/lib/REST/NextcloudNews/V1_2.php index 7ec195c..205fa73 100644 --- a/lib/REST/NextcloudNews/V1_2.php +++ b/lib/REST/NextcloudNews/V1_2.php @@ -18,7 +18,6 @@ use JKingWeb\Arsse\REST\Exception; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { public const VERSION = "11.0.5"; @@ -86,19 +85,19 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { if ($req->getAttribute("authenticated", false)) { Arsse::$user->id = $req->getAttribute("authenticatedUser"); } else { - return new EmptyResponse(401); + return HTTP::respEmpty(401); } // normalize the input $data = (string) $req->getBody(); if ($data) { // if the entity body is not JSON according to content type, return "415 Unsupported Media Type" if (!HTTP::matchType($req, "", self::ACCEPTED_TYPE)) { - return new EmptyResponse(415, ['Accept' => self::ACCEPTED_TYPE]); + return HTTP::respEmpty(415, ['Accept' => self::ACCEPTED_TYPE]); } $data = @json_decode($data, true); if (json_last_error() !== \JSON_ERROR_NONE) { // if the body could not be parsed as JSON, return "400 Bad Request" - return new EmptyResponse(400); + return HTTP::respEmpty(400); } } else { $data = []; @@ -117,10 +116,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // @codeCoverageIgnoreStart } catch (Exception $e) { // if there was a REST exception return 400 - return new EmptyResponse(400); + return HTTP::respEmpty(400); } catch (AbstractException $e) { // if there was any other Arsse exception return 500 - return new EmptyResponse(500); + return HTTP::respEmpty(500); } // @codeCoverageIgnoreEnd } @@ -162,11 +161,11 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { return $this->paths[$url][$method]; } else { // otherwise return 405 - return new EmptyResponse(405, ['Allow' => implode(", ", array_keys($this->paths[$url]))]); + return HTTP::respEmpty(405, ['Allow' => implode(", ", array_keys($this->paths[$url]))]); } } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -268,13 +267,13 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { if (in_array("GET", $allowed)) { array_unshift($allowed, "HEAD"); } - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => implode(",", $allowed), 'Accept' => self::ACCEPTED_TYPE, ]); } else { // if the path is not supported, return 404 - return new EmptyResponse(404); + return HTTP::respEmpty(404); } } @@ -294,12 +293,12 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { // folder already exists - case 10236: return new EmptyResponse(409); + case 10236: return HTTP::respEmpty(409); // folder name not acceptable case 10231: - case 10232: return new EmptyResponse(422); + case 10232: return HTTP::respEmpty(422); // other errors related to input - default: return new EmptyResponse(400); // @codeCoverageIgnore + default: return HTTP::respEmpty(400); // @codeCoverageIgnore } } $folder = $this->folderTranslate(Arsse::$db->folderPropertiesGet(Arsse::$user->id, $folder)); @@ -313,9 +312,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->folderRemove(Arsse::$user->id, (int) $url[1]); } catch (ExceptionInput $e) { // folder does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // rename a folder (also supports moving nesting folders, but this is not a feature of the API) @@ -325,24 +324,24 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { // folder does not exist - case 10239: return new EmptyResponse(404); + case 10239: return HTTP::respEmpty(404); // folder already exists - case 10236: return new EmptyResponse(409); + case 10236: return HTTP::respEmpty(409); // folder name not acceptable case 10231: - case 10232: return new EmptyResponse(422); + case 10232: return HTTP::respEmpty(422); // other errors related to input - default: return new EmptyResponse(400); // @codeCoverageIgnore + default: return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark all articles associated with a folder as read protected function folderMarkRead(array $url, array $data): ResponseInterface { if (!ValueInfo::id($data['newestItemId'])) { // if the item ID is invalid (i.e. not a positive integer), this is an error - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // build the context $c = (new Context)->hidden(false); @@ -353,15 +352,15 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); } catch (ExceptionInput $e) { // folder does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // return list of feeds which should be refreshed protected function feedListStale(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } // list stale feeds which should be checked for updates $feeds = Arsse::$db->feedListStale(); @@ -376,21 +375,21 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { // refresh a feed protected function feedUpdate(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } try { Arsse::$db->feedUpdate($data['feedId']); } catch (ExceptionInput $e) { switch ($e->getCode()) { case 10239: // feed does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); case 10237: // feed ID invalid - return new EmptyResponse(422); + return HTTP::respEmpty(422); default: // other errors related to input - return new EmptyResponse(400); // @codeCoverageIgnore + return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // add a new feed @@ -401,10 +400,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { $id = Arsse::$db->subscriptionAdd(Arsse::$user->id, (string) $data['url']); } catch (ExceptionInput $e) { // feed already exists - return new EmptyResponse(409); + return HTTP::respEmpty(409); } catch (FeedException $e) { // feed could not be retrieved - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // if a folder was specified, move the feed to the correct folder; silently ignore errors if ($data['folderId']) { @@ -447,9 +446,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->subscriptionRemove(Arsse::$user->id, (int) $url[1]); } catch (ExceptionInput $e) { // feed does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // rename a feed @@ -459,22 +458,22 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { // subscription does not exist - case 10239: return new EmptyResponse(404); + case 10239: return HTTP::respEmpty(404); // name is invalid case 10231: - case 10232: return new EmptyResponse(422); + case 10232: return HTTP::respEmpty(422); // other errors related to input - default: return new EmptyResponse(400); // @codeCoverageIgnore + default: return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // move a feed to a folder protected function subscriptionMove(array $url, array $data): ResponseInterface { // if no folder is specified this is an error if (!isset($data['folderId'])) { - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // perform the move try { @@ -482,22 +481,22 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { } catch (ExceptionInput $e) { switch ($e->getCode()) { case 10239: // subscription does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); case 10235: // folder does not exist case 10237: // folder ID is invalid - return new EmptyResponse(422); + return HTTP::respEmpty(422); default: // other errors related to input - return new EmptyResponse(400); // @codeCoverageIgnore + return HTTP::respEmpty(400); // @codeCoverageIgnore } } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark all articles associated with a subscription as read protected function subscriptionMarkRead(array $url, array $data): ResponseInterface { if (!ValueInfo::id($data['newestItemId'])) { // if the item ID is invalid (i.e. not a positive integer), this is an error - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // build the context $c = (new Context)->hidden(false); @@ -508,9 +507,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); } catch (ExceptionInput $e) { // subscription does not exist - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // list articles and their properties @@ -579,7 +578,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { ], [$reverse ? "edition desc" : "edition"]); } catch (ExceptionInput $e) { // ID of subscription or folder is not valid - return new EmptyResponse(422); + return HTTP::respEmpty(422); } $out = []; foreach ($items as $item) { @@ -593,14 +592,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function articleMarkReadAll(array $url, array $data): ResponseInterface { if (!ValueInfo::id($data['newestItemId'])) { // if the item ID is invalid (i.e. not a positive integer), this is an error - return new EmptyResponse(422); + return HTTP::respEmpty(422); } // build the context $c = (new Context)->hidden(false); $c->editionRange(null, (int) $data['newestItemId']); // perform the operation Arsse::$db->articleMark(Arsse::$user->id, ['read' => true], $c); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark a single article as read @@ -614,9 +613,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c); } catch (ExceptionInput $e) { // ID is not valid - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark a single article as read @@ -630,9 +629,9 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c); } catch (ExceptionInput $e) { // ID is not valid - return new EmptyResponse(404); + return HTTP::respEmpty(404); } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark an array of articles as read @@ -646,7 +645,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['read' => $set], $c); } catch (ExceptionInput $e) { } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // mark an array of articles as starred @@ -660,7 +659,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$db->articleMark(Arsse::$user->id, ['starred' => $set], $c); } catch (ExceptionInput $e) { } - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function userStatus(array $url, array $data): ResponseInterface { @@ -674,18 +673,18 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler { protected function cleanupBefore(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } Service::cleanupPre(); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } protected function cleanupAfter(array $url, array $data): ResponseInterface { if (!$this->isAdmin()) { - return new EmptyResponse(403); + return HTTP::respEmpty(403); } Service::cleanupPost(); - return new EmptyResponse(204); + return HTTP::respEmpty(204); } // return the server version diff --git a/lib/REST/NextcloudNews/Versions.php b/lib/REST/NextcloudNews/Versions.php index 95ee0bf..503fef1 100644 --- a/lib/REST/NextcloudNews/Versions.php +++ b/lib/REST/NextcloudNews/Versions.php @@ -6,10 +6,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST\NextcloudNews; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; class Versions implements \JKingWeb\Arsse\REST\Handler { public function __construct() { @@ -18,12 +18,12 @@ class Versions implements \JKingWeb\Arsse\REST\Handler { public function dispatch(ServerRequestInterface $req): ResponseInterface { if (!preg_match("<^/?$>D", $req->getRequestTarget())) { // if the request path is more than an empty string or a slash, the client is probably trying a version we don't support - return new EmptyResponse(404); + return HTTP::respEmpty(404); } switch ($req->getMethod()) { case "OPTIONS": // if the request method is OPTIONS, respond accordingly - return new EmptyResponse(204, ['Allow' => "HEAD,GET"]); + return HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]); case "GET": // otherwise return the supported versions $out = [ @@ -34,7 +34,7 @@ class Versions implements \JKingWeb\Arsse\REST\Handler { return new Response($out); default: // if any other method was used, this is an error - return new EmptyResponse(405, ['Allow' => "HEAD,GET"]); + return HTTP::respEmpty(405, ['Allow' => "HEAD,GET"]); } } } diff --git a/lib/REST/TinyTinyRSS/API.php b/lib/REST/TinyTinyRSS/API.php index e167fa4..d8fb5ca 100644 --- a/lib/REST/TinyTinyRSS/API.php +++ b/lib/REST/TinyTinyRSS/API.php @@ -12,6 +12,7 @@ use JKingWeb\Arsse\Service; use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Misc\Date; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\ValueInfo as V; use JKingWeb\Arsse\AbstractException; use JKingWeb\Arsse\ExceptionType; @@ -21,7 +22,6 @@ use JKingWeb\Arsse\Feed\Exception as FeedException; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; class API extends \JKingWeb\Arsse\REST\AbstractHandler { public const LEVEL = 15; // emulated API level @@ -96,11 +96,11 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { public function dispatch(ServerRequestInterface $req): ResponseInterface { if (!preg_match("<^(?:/(?:index\.php)?)?$>D", $req->getRequestTarget())) { // reject paths other than the index - return new EmptyResponse(404); + return HTTP::respEmpty(404); } if ($req->getMethod() === "OPTIONS") { // respond to OPTIONS rquests; the response is a fib, as we technically accept any type or method - return new EmptyResponse(204, [ + return HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => implode(", ", self::ACCEPTED_TYPES), ]); @@ -125,7 +125,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$user->id = $req->getAttribute("authenticatedUser"); } elseif (Arsse::$conf->userHTTPAuthRequired || Arsse::$conf->userPreAuth || $req->getAttribute("authenticationFailed", false)) { // otherwise if HTTP authentication failed or is required, deny access at the HTTP level - return new EmptyResponse(401); + return HTTP::respEmpty(401); } if (strtolower((string) $data['op']) !== "login") { // unless logging in, a session identifier is required @@ -148,7 +148,7 @@ class API extends \JKingWeb\Arsse\REST\AbstractHandler { 'content' => $e->getData(), ]); } catch (AbstractException $e) { - return new EmptyResponse(500); + return HTTP::respEmpty(500); } } else { // absence of a request body indicates an error diff --git a/lib/REST/TinyTinyRSS/Icon.php b/lib/REST/TinyTinyRSS/Icon.php index dd718bc..37f2ce8 100644 --- a/lib/REST/TinyTinyRSS/Icon.php +++ b/lib/REST/TinyTinyRSS/Icon.php @@ -7,10 +7,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\REST\TinyTinyRSS; use JKingWeb\Arsse\Arsse; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\ExceptionInput; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse as Response; class Icon extends \JKingWeb\Arsse\REST\AbstractHandler { public function __construct() { @@ -22,25 +22,25 @@ class Icon extends \JKingWeb\Arsse\REST\AbstractHandler { Arsse::$user->id = $req->getAttribute("authenticatedUser"); } elseif ($req->getAttribute("authenticationFailed", false) || Arsse::$conf->userHTTPAuthRequired) { // otherwise if HTTP authentication failed or did not occur when it is required, deny access at the HTTP level - return new Response(401); + return HTTP::respEmpty(401); } if ($req->getMethod() !== "GET") { // only GET requests are allowed - return new Response(405, ['Allow' => "GET"]); + return HTTP::respEmpty(405, ['Allow' => "GET"]); } elseif (!preg_match("<^(\d+)\.ico$>D", $req->getRequestTarget(), $match) || !((int) $match[1])) { - return new Response(404); + return HTTP::respEmpty(404); } try { $url = Arsse::$db->subscriptionIcon(Arsse::$user->id ?? null, (int) $match[1], false)['url'] ?? null; if (!$url) { - return new Response(404); + return HTTP::respEmpty(404); } if (($pos = strpos($url, "\r")) !== false || ($pos = strpos($url, "\n")) !== false) { $url = substr($url, 0, $pos); } - return new Response(301, ['Location' => $url]); + return HTTP::respEmpty(301, ['Location' => $url]); } catch (ExceptionInput $e) { - return new Response(404); + return HTTP::respEmpty(404); } } } diff --git a/tests/cases/REST/Fever/TestAPI.php b/tests/cases/REST/Fever/TestAPI.php index 6a618b6..59d1858 100644 --- a/tests/cases/REST/Fever/TestAPI.php +++ b/tests/cases/REST/Fever/TestAPI.php @@ -9,6 +9,7 @@ namespace JKingWeb\Arsse\TestCase\REST\Fever; use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Db\ExceptionInput; @@ -17,7 +18,6 @@ use JKingWeb\Arsse\REST\Fever\API; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse; use Laminas\Diactoros\Response\XmlResponse; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\Fever\API */ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { @@ -194,7 +194,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { public function provideTokenAuthenticationRequests(): iterable { $success = new JsonResponse(['auth' => 1]); $failure = new JsonResponse(['auth' => 0]); - $denied = new EmptyResponse(401); + $denied = HTTP::respEmpty(401); return [ [false, true, null, [], ['api' => null], $failure], [false, false, null, [], ['api' => null], $failure], @@ -421,8 +421,8 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { public function provideInvalidRequests(): iterable { return [ - 'Not an API request' => ["", "", "POST", null, new EmptyResponse(404)], - 'Wrong method' => ["api", "", "PUT", null, new EmptyResponse(405, ['Allow' => "OPTIONS,POST"])], + 'Not an API request' => ["", "", "POST", null, HTTP::respEmpty(404)], + 'Wrong method' => ["api", "", "PUT", null, HTTP::respEmpty(405, ['Allow' => "OPTIONS,POST"])], 'Non-standard method' => ["api", "", "GET", null, new JsonResponse([])], 'Wrong content type' => ["api", '{"api_key":"validToken"}', "POST", "application/json", new JsonResponse([])], // some clients send nonsensical content types; Fever seems to have allowed this 'Non-standard content type' => ["api", '{"api_key":"validToken"}', "POST", "multipart/form-data; boundary=33b68964f0de4c1f-5144aa6caaa6e4a8-18bfaf416a1786c8-5c5053a45f221bc1", new JsonResponse([])], // some clients send nonsensical content types; Fever seems to have allowed this @@ -494,7 +494,7 @@ class TestAPI extends \JKingWeb\Arsse\Test\AbstractTest { } public function testAnswerOptionsRequest(): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => "application/x-www-form-urlencoded, multipart/form-data", ]); diff --git a/tests/cases/REST/Miniflux/TestStatus.php b/tests/cases/REST/Miniflux/TestStatus.php index bcf81d1..cf573e3 100644 --- a/tests/cases/REST/Miniflux/TestStatus.php +++ b/tests/cases/REST/Miniflux/TestStatus.php @@ -6,10 +6,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\REST\Miniflux; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\Miniflux\Status; use JKingWeb\Arsse\REST\Miniflux\V1; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\Status */ @@ -23,12 +23,12 @@ class TestStatus extends \JKingWeb\Arsse\Test\AbstractTest { public function provideRequests(): iterable { return [ ["/version", "GET", new TextResponse(V1::VERSION)], - ["/version", "POST", new EmptyResponse(405, ['Allow' => "HEAD, GET"])], - ["/version", "OPTIONS", new EmptyResponse(204, ['Allow' => "HEAD, GET"])], + ["/version", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])], + ["/version", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])], ["/healthcheck", "GET", new TextResponse("OK")], - ["/healthcheck", "POST", new EmptyResponse(405, ['Allow' => "HEAD, GET"])], - ["/healthcheck", "OPTIONS", new EmptyResponse(204, ['Allow' => "HEAD, GET"])], - ["/version/", "GET", new EmptyResponse(404)], + ["/healthcheck", "POST", HTTP::respEmpty(405, ['Allow' => "HEAD, GET"])], + ["/healthcheck", "OPTIONS", HTTP::respEmpty(204, ['Allow' => "HEAD, GET"])], + ["/version/", "GET", HTTP::respEmpty(404)], ]; } } diff --git a/tests/cases/REST/Miniflux/TestV1.php b/tests/cases/REST/Miniflux/TestV1.php index 9623fd3..8961047 100644 --- a/tests/cases/REST/Miniflux/TestV1.php +++ b/tests/cases/REST/Miniflux/TestV1.php @@ -14,6 +14,7 @@ use JKingWeb\Arsse\Context\RootContext; use JKingWeb\Arsse\Context\UnionContext; use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\REST\Miniflux\V1; @@ -26,7 +27,6 @@ use JKingWeb\Arsse\User\ExceptionInput as UserExceptionInput; use JKingWeb\Arsse\Test\Result; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; use Laminas\Diactoros\Response\TextResponse; /** @covers \JKingWeb\Arsse\REST\Miniflux\V1 */ @@ -102,7 +102,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideAuthResponses */ public function testAuthenticateAUser($token, bool $auth, bool $success): void { - $exp = $success ? new EmptyResponse(404) : new ErrorResponse("401", 401); + $exp = $success ? HTTP::respEmpty(404) : new ErrorResponse("401", 401); $user = "john.doe@example.com"; if ($token !== null) { $headers = ['X-Auth-Token' => $token]; @@ -133,7 +133,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideInvalidPaths */ public function testRespondToInvalidPaths($path, $method, $code, $allow = null): void { - $exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []); + $exp = HTTP::respEmpty($code, $allow ? ['Allow' => $allow] : []); $this->assertMessage($exp, $this->req($method, $path)); } @@ -148,7 +148,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { /** @dataProvider provideOptionsRequests */ public function testRespondToOptionsRequests(string $url, string $allow, string $accept): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => $allow, 'Accept' => $accept, ]); @@ -382,7 +382,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { Arsse::$user->method("remove")->willReturn(true); Arsse::$user->expects($this->exactly(1))->method("lookup")->with(2112); Arsse::$user->expects($this->exactly(1))->method("remove")->with("john.doe@example.com"); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/users/2112")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/users/2112")); } public function testDeleteAMissingUser(): void { @@ -484,7 +484,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testDeleteARealCategory(): void { $this->dbMock->folderRemove->returns(true)->throws(new ExceptionInput("subjectMissing")); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/categories/2112")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/categories/2112")); $this->dbMock->folderRemove->calledWith("john.doe@example.com", 2111); $this->assertMessage(new ErrorResponse("404", 404), $this->req("DELETE", "/categories/47")); $this->dbMock->folderRemove->calledWith("john.doe@example.com", 46); @@ -497,7 +497,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { ['id' => 2112], ]))); $this->dbMock->subscriptionRemove->returns(true); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/categories/1")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/categories/1")); Phony::inOrder( $this->dbMock->begin->calledWith(), $this->dbMock->subscriptionList->calledWith("john.doe@example.com", null, false), @@ -680,7 +680,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function testDeleteAFeed(): void { $this->dbMock->subscriptionRemove->returns(true); - $this->assertMessage(new EmptyResponse(204), $this->req("DELETE", "/feeds/2112")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("DELETE", "/feeds/2112")); $this->dbMock->subscriptionRemove->calledWith(Arsse::$user->id, 2112); } @@ -864,9 +864,9 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { [['entry_ids' => [1], 'status' => 1], null, new ErrorResponse(["InvalidInputType", 'field' => "status", 'expected' => "string", 'actual' => "integer"], 422)], [['entry_ids' => [0], 'status' => "read"], null, new ErrorResponse(["InvalidInputValue", 'field' => "entry_ids"], 422)], [['entry_ids' => [1], 'status' => "reread"], null, new ErrorResponse(["InvalidInputValue", 'field' => "status"], 422)], - [['entry_ids' => [1, 2], 'status' => "read"], ['read' => true, 'hidden' => false], new EmptyResponse(204)], - [['entry_ids' => [1, 2], 'status' => "unread"], ['read' => false, 'hidden' => false], new EmptyResponse(204)], - [['entry_ids' => [1, 2], 'status' => "removed"], ['read' => true, 'hidden' => true], new EmptyResponse(204)], + [['entry_ids' => [1, 2], 'status' => "read"], ['read' => true, 'hidden' => false], HTTP::respEmpty(204)], + [['entry_ids' => [1, 2], 'status' => "unread"], ['read' => false, 'hidden' => false], HTTP::respEmpty(204)], + [['entry_ids' => [1, 2], 'status' => "removed"], ['read' => true, 'hidden' => true], HTTP::respEmpty(204)], ]; } @@ -889,13 +889,13 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { self::clearData(); $c = (new Context)->hidden(false); return [ - ["/users/42/mark-all-as-read", $c, 1123, new EmptyResponse(204)], + ["/users/42/mark-all-as-read", $c, 1123, HTTP::respEmpty(204)], ["/users/2112/mark-all-as-read", $c, null, new ErrorResponse("403", 403)], - ["/feeds/47/mark-all-as-read", (clone $c)->subscription(47), 2112, new EmptyResponse(204)], + ["/feeds/47/mark-all-as-read", (clone $c)->subscription(47), 2112, HTTP::respEmpty(204)], ["/feeds/2112/mark-all-as-read", (clone $c)->subscription(2112), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], - ["/categories/47/mark-all-as-read", (clone $c)->folder(46), 1337, new EmptyResponse(204)], + ["/categories/47/mark-all-as-read", (clone $c)->folder(46), 1337, HTTP::respEmpty(204)], ["/categories/2112/mark-all-as-read", (clone $c)->folder(2111), new ExceptionInput("idMissing"), new ErrorResponse("404", 404)], - ["/categories/1/mark-all-as-read", (clone $c)->folderShallow(0), 6666, new EmptyResponse(204)], + ["/categories/1/mark-all-as-read", (clone $c)->folderShallow(0), 6666, HTTP::respEmpty(204)], ]; } @@ -929,15 +929,15 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideBookmarkTogglings(): iterable { self::clearData(); return [ - [1, true, new EmptyResponse(204)], - [0, false, new EmptyResponse(204)], + [1, true, HTTP::respEmpty(204)], + [0, false, HTTP::respEmpty(204)], [new ExceptionInput("subjectMissing"), null, new ErrorResponse("404", 404)], ]; } public function testRefreshAFeed(): void { $this->dbMock->subscriptionPropertiesGet->returns([]); - $this->assertMessage(new EmptyResponse(204), $this->req("PUT", "/feeds/47/refresh")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("PUT", "/feeds/47/refresh")); $this->dbMock->subscriptionPropertiesGet->calledWith(Arsse::$user->id, 47); } @@ -948,7 +948,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRefreshAllFeeds(): void { - $this->assertMessage(new EmptyResponse(204), $this->req("PUT", "/feeds/refresh")); + $this->assertMessage(HTTP::respEmpty(204), $this->req("PUT", "/feeds/refresh")); } /** @dataProvider provideImports */ diff --git a/tests/cases/REST/NextcloudNews/TestV1_2.php b/tests/cases/REST/NextcloudNews/TestV1_2.php index f58f87d..08f1f70 100644 --- a/tests/cases/REST/NextcloudNews/TestV1_2.php +++ b/tests/cases/REST/NextcloudNews/TestV1_2.php @@ -11,13 +11,13 @@ use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Misc\Date; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\REST\NextcloudNews\V1_2; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\NextcloudNews\V1_2 */ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { @@ -336,13 +336,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testSendAuthenticationChallenge(): void { - $exp = new EmptyResponse(401); + $exp = HTTP::respEmpty(401); $this->assertMessage($exp, $this->req("GET", "/", "", [], false)); } /** @dataProvider provideInvalidPaths */ public function testRespondToInvalidPaths($path, $method, $code, $allow = null): void { - $exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []); + $exp = HTTP::respEmpty($code, $allow ? ['Allow' => $allow] : []); $this->assertMessage($exp, $this->req($method, $path)); } @@ -374,16 +374,16 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRespondToInvalidInputTypes(): void { - $exp = new EmptyResponse(415, ['Accept' => "application/json"]); + $exp = HTTP::respEmpty(415, ['Accept' => "application/json"]); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '', ['Content-Type' => "application/xml"])); - $exp = new EmptyResponse(400); + $exp = HTTP::respEmpty(400); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '')); $this->assertMessage($exp, $this->req("PUT", "/folders/1", '', ['Content-Type' => null])); } /** @dataProvider provideOptionsRequests */ public function testRespondToOptionsRequests(string $url, string $allow, string $accept): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => $allow, 'Accept' => $accept, ]); @@ -436,19 +436,19 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { [['name' => "Software"], false, 1, new Response(['folders' => [['id' => 1, 'name' => "Software"]]])], [['name' => "Hardware"], true, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])], [['name' => "Hardware"], false, "2", new Response(['folders' => [['id' => 2, 'name' => "Hardware"]]])], - [['name' => "Software"], true, new ExceptionInput("constraintViolation"), new EmptyResponse(409)], - [['name' => ""], true, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => " "], true, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => null], true, new ExceptionInput("missing"), new EmptyResponse(422)], + [['name' => "Software"], true, new ExceptionInput("constraintViolation"), HTTP::respEmpty(409)], + [['name' => ""], true, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => " "], true, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => null], true, new ExceptionInput("missing"), HTTP::respEmpty(422)], ]; } public function testRemoveAFolder(): void { $this->dbMock->folderRemove->with($this->userId, 1)->returns(true)->throws(new ExceptionInput("subjectMissing")); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("DELETE", "/folders/1")); // fail on the second invocation because it no longer exists - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("DELETE", "/folders/1")); $this->dbMock->folderRemove->times(2)->calledWith($this->userId, 1); } @@ -467,12 +467,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function provideFolderRenamings(): array { return [ - [['name' => "Software"], 1, true, new EmptyResponse(204)], - [['name' => "Software"], 2, new ExceptionInput("constraintViolation"), new EmptyResponse(409)], - [['name' => "Software"], 3, new ExceptionInput("subjectMissing"), new EmptyResponse(404)], - [['name' => ""], 2, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => " "], 2, new ExceptionInput("whitespace"), new EmptyResponse(422)], - [['name' => null], 2, new ExceptionInput("missing"), new EmptyResponse(422)], + [['name' => "Software"], 1, true, HTTP::respEmpty(204)], + [['name' => "Software"], 2, new ExceptionInput("constraintViolation"), HTTP::respEmpty(409)], + [['name' => "Software"], 3, new ExceptionInput("subjectMissing"), HTTP::respEmpty(404)], + [['name' => ""], 2, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => " "], 2, new ExceptionInput("whitespace"), HTTP::respEmpty(422)], + [['name' => null], 2, new ExceptionInput("missing"), HTTP::respEmpty(422)], ]; } @@ -540,19 +540,19 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { return [ [['url' => "http://example.com/news.atom", 'folderId' => 3], 2112, 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new Response(['feeds' => [$this->feeds['rest'][0]]])], [['url' => "http://example.org/news.atom", 'folderId' => 8], 42, 4758915, $this->feeds['db'][1], true, new Response(['feeds' => [$this->feeds['rest'][1]], 'newestItemId' => 4758915])], - [['url' => "http://example.com/news.atom", 'folderId' => 3], new ExceptionInput("constraintViolation"), 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), new EmptyResponse(409)], - [['url' => "http://example.org/news.atom", 'folderId' => 8], new ExceptionInput("constraintViolation"), 4758915, $this->feeds['db'][1], true, new EmptyResponse(409)], - [[], $feedException, 0, [], false, new EmptyResponse(422)], + [['url' => "http://example.com/news.atom", 'folderId' => 3], new ExceptionInput("constraintViolation"), 0, $this->feeds['db'][0], new ExceptionInput("idMissing"), HTTP::respEmpty(409)], + [['url' => "http://example.org/news.atom", 'folderId' => 8], new ExceptionInput("constraintViolation"), 4758915, $this->feeds['db'][1], true, HTTP::respEmpty(409)], + [[], $feedException, 0, [], false, HTTP::respEmpty(422)], [['url' => "http://example.net/news.atom", 'folderId' => -1], 47, 2112, $this->feeds['db'][2], new ExceptionInput("typeViolation"), new Response(['feeds' => [$this->feeds['rest'][2]], 'newestItemId' => 2112])], ]; } public function testRemoveASubscription(): void { $this->dbMock->subscriptionRemove->with($this->userId, 1)->returns(true)->throws(new ExceptionInput("subjectMissing")); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("DELETE", "/feeds/1")); // fail on the second invocation because it no longer exists - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("DELETE", "/feeds/1")); $this->dbMock->subscriptionRemove->times(2)->calledWith($this->userId, 1); } @@ -571,17 +571,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, ['folder' => 2112])->throws(new ExceptionInput("idMissing")); // folder does not exist $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, ['folder' => -1])->throws(new ExceptionInput("typeViolation")); // folder is invalid $this->dbMock->subscriptionPropertiesSet->with($this->userId, 42, $this->anything())->throws(new ExceptionInput("subjectMissing")); // subscription does not exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[0]))); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[1]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[2]))); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/feeds/42/move", json_encode($in[3]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[4]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/move", json_encode($in[5]))); } @@ -601,17 +601,17 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, $this->identicalTo(['title' => ""]))->throws(new ExceptionInput("missing")); $this->dbMock->subscriptionPropertiesSet->with($this->userId, 1, $this->identicalTo(['title' => false]))->throws(new ExceptionInput("missing")); $this->dbMock->subscriptionPropertiesSet->with($this->userId, 42, $this->anything())->throws(new ExceptionInput("subjectMissing")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[0]))); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[1]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[2]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[3]))); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/feeds/42/rename", json_encode($in[4]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/rename", json_encode($in[6]))); } @@ -633,7 +633,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testListStaleFeedsWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/feeds/all")); $this->dbMock->feedListStale->never()->called(); } @@ -649,11 +649,11 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->feedUpdate->with(42)->returns(true); $this->dbMock->feedUpdate->with(2112)->throws(new ExceptionInput("subjectMissing")); $this->dbMock->feedUpdate->with($this->lessThan(1))->throws(new ExceptionInput("typeViolation")); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[0]))); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[1]))); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[2]))); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[3]))); $this->assertMessage($exp, $this->req("GET", "/feeds/update", json_encode($in[4]))); @@ -661,7 +661,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testUpdateAFeedWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/feeds/update", ['feedId' => 42])); $this->dbMock->feedUpdate->never()->called(); } @@ -684,7 +684,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $t = Date::normalize(time()); $out = new Result($this->v($this->articles['db'])); $r200 = new Response(['items' => $this->articles['rest']]); - $r422 = new EmptyResponse(422); + $r422 = HTTP::respEmpty(422); return [ ["/items", [], clone $c, $out, $r200], ["/items", ['type' => 0, 'id' => 42], (clone $c)->subscription(42), new ExceptionInput("idMissing"), $r422], @@ -720,13 +720,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $in = json_encode(['newestItemId' => 2112]); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(1)->editionRange(null, 2112)->hidden(false)))->returns(42); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->folder(42)->editionRange(null, 2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // folder doesn't exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read?newestItemId=2112")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read")); $this->assertMessage($exp, $this->req("PUT", "/folders/1/read?newestItemId=ook")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/folders/42/read", $in)); } @@ -735,13 +735,13 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $in = json_encode(['newestItemId' => 2112]); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(1)->editionRange(null, 2112)->hidden(false)))->returns(42); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->subscription(42)->editionRange(null, 2112)->hidden(false)))->throws(new ExceptionInput("idMissing")); // subscription doesn't exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read?newestItemId=2112")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read")); $this->assertMessage($exp, $this->req("PUT", "/feeds/1/read?newestItemId=ook")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/feeds/42/read", $in)); } @@ -749,10 +749,10 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $read = ['read' => true]; $in = json_encode(['newestItemId' => 2112]); $this->dbMock->articleMark->with($this->userId, $read, $this->equalTo((new Context)->editionRange(null, 2112)))->returns(42); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/items/read", $in)); $this->assertMessage($exp, $this->req("PUT", "/items/read?newestItemId=2112")); - $exp = new EmptyResponse(422); + $exp = HTTP::respEmpty(422); $this->assertMessage($exp, $this->req("PUT", "/items/read")); $this->assertMessage($exp, $this->req("PUT", "/items/read?newestItemId=ook")); } @@ -770,12 +770,12 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleMark->with($this->userId, $star, $this->equalTo((new Context)->article(2112)))->throws(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist $this->dbMock->articleMark->with($this->userId, $unstar, $this->equalTo((new Context)->article(4)))->returns(42); $this->dbMock->articleMark->with($this->userId, $unstar, $this->equalTo((new Context)->article(1337)))->throws(new ExceptionInput("subjectMissing")); // article doesn't exist doesn't exist - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/items/1/read")); $this->assertMessage($exp, $this->req("PUT", "/items/2/unread")); $this->assertMessage($exp, $this->req("PUT", "/items/1/3/star")); $this->assertMessage($exp, $this->req("PUT", "/items/4400/4/unstar")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("PUT", "/items/42/read")); $this->assertMessage($exp, $this->req("PUT", "/items/47/unread")); $this->assertMessage($exp, $this->req("PUT", "/items/1/2112/star")); @@ -801,7 +801,7 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->articleMark->with($this->userId, $this->anything(), $this->anything())->returns(42); $this->dbMock->articleMark->with($this->userId, $this->anything(), $this->equalTo((new Context)->editions([])))->throws(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples $this->dbMock->articleMark->with($this->userId, $this->anything(), $this->equalTo((new Context)->articles([])))->throws(new ExceptionInput("tooShort")); // data model function requires one valid integer for multiples - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("PUT", "/items/read/multiple")); $this->assertMessage($exp, $this->req("PUT", "/items/unread/multiple")); $this->assertMessage($exp, $this->req("PUT", "/items/star/multiple")); @@ -860,28 +860,28 @@ class TestV1_2 extends \JKingWeb\Arsse\Test\AbstractTest { public function testCleanUpBeforeUpdate(): void { $this->dbMock->feedCleanup->with()->returns(true); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("GET", "/cleanup/before-update")); $this->dbMock->feedCleanup->calledWith(); } public function testCleanUpBeforeUpdateWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/cleanup/before-update")); $this->dbMock->feedCleanup->never()->called(); } public function testCleanUpAfterUpdate(): void { $this->dbMock->articleCleanup->with()->returns(true); - $exp = new EmptyResponse(204); + $exp = HTTP::respEmpty(204); $this->assertMessage($exp, $this->req("GET", "/cleanup/after-update")); $this->dbMock->articleCleanup->calledWith(); } public function testCleanUpAfterUpdateWithoutAuthority(): void { $this->userMock->propertiesGet->returns(['admin' => false]); - $exp = new EmptyResponse(403); + $exp = HTTP::respEmpty(403); $this->assertMessage($exp, $this->req("GET", "/cleanup/after-update")); $this->dbMock->feedCleanup->never()->called(); } diff --git a/tests/cases/REST/NextcloudNews/TestVersions.php b/tests/cases/REST/NextcloudNews/TestVersions.php index b5d5679..a254772 100644 --- a/tests/cases/REST/NextcloudNews/TestVersions.php +++ b/tests/cases/REST/NextcloudNews/TestVersions.php @@ -6,10 +6,10 @@ declare(strict_types=1); namespace JKingWeb\Arsse\TestCase\REST\NextcloudNews; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\REST\NextcloudNews\Versions; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\NextcloudNews\Versions */ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { @@ -32,17 +32,17 @@ class TestVersions extends \JKingWeb\Arsse\Test\AbstractTest { } public function testRespondToOptionsRequest(): void { - $exp = new EmptyResponse(204, ['Allow' => "HEAD,GET"]); + $exp = HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]); $this->assertMessage($exp, $this->req("OPTIONS", "/")); } public function testUseIncorrectMethod(): void { - $exp = new EmptyResponse(405, ['Allow' => "HEAD,GET"]); + $exp = HTTP::respEmpty(405, ['Allow' => "HEAD,GET"]); $this->assertMessage($exp, $this->req("POST", "/")); } public function testUseIncorrectPath(): void { - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("GET", "/ook")); $this->assertMessage($exp, $this->req("OPTIONS", "/ook")); } diff --git a/tests/cases/REST/TestREST.php b/tests/cases/REST/TestREST.php index 0ba6ead..059803d 100644 --- a/tests/cases/REST/TestREST.php +++ b/tests/cases/REST/TestREST.php @@ -12,13 +12,13 @@ use JKingWeb\Arsse\REST; use JKingWeb\Arsse\REST\Exception501; use JKingWeb\Arsse\REST\NextcloudNews\V1_2 as NCN; use JKingWeb\Arsse\REST\TinyTinyRSS\API as TTRSS; +use JKingWeb\Arsse\Misc\HTTP; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Request; use Laminas\Diactoros\Response; use Laminas\Diactoros\ServerRequest; use Laminas\Diactoros\Response\TextResponse; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST */ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { @@ -96,7 +96,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { public function testSendAuthenticationChallenges(): void { self::setConf(); $r = new REST(); - $in = new EmptyResponse(401); + $in = HTTP::respEmpty(401); $exp = $in->withHeader("WWW-Authenticate", 'Basic realm="OOK", charset="UTF-8"'); $act = $r->challenge($in, "OOK"); $this->assertMessage($exp, $act); @@ -190,8 +190,8 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { public function testAddCorsHeaders(string $reqMethod, array $reqHeaders, array $resHeaders, array $expHeaders): void { $r = new REST(); $req = new Request("", $reqMethod, "php://memory", $reqHeaders); - $res = new EmptyResponse(204, $resHeaders); - $exp = new EmptyResponse(204, $expHeaders); + $res = HTTP::respEmpty(204, $resHeaders); + $exp = HTTP::respEmpty(204, $expHeaders); $act = $r->corsApply($res, $req); $this->assertMessage($exp, $act); } @@ -268,21 +268,21 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { $stream = fopen("php://memory", "w+b"); fwrite($stream, "ook"); return [ - [new EmptyResponse(204), new EmptyResponse(204)], - [new EmptyResponse(401), new EmptyResponse(401, ['WWW-Authenticate' => "Fake Value"])], - [new EmptyResponse(204, ['Allow' => "PUT"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "PUT,OPTIONS"]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => ["PUT", "OPTIONS"]]), new EmptyResponse(204, ['Allow' => "PUT, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => ["PUT, DELETE", "OPTIONS"]]), new EmptyResponse(204, ['Allow' => "PUT, DELETE, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "HEAD,GET"]), new EmptyResponse(204, ['Allow' => "HEAD, GET, OPTIONS"])], - [new EmptyResponse(204, ['Allow' => "GET"]), new EmptyResponse(204, ['Allow' => "GET, HEAD, OPTIONS"])], - [new TextResponse("ook", 200), new TextResponse("ook", 200, ['Content-Length' => "3"])], - [new TextResponse("", 200), new TextResponse("", 200, ['Content-Length' => "0"])], - [new TextResponse("ook", 404), new TextResponse("ook", 404, ['Content-Length' => "3"])], - [new TextResponse("", 404), new TextResponse("", 404)], - [new Response($stream, 200), new Response($stream, 200, ['Content-Length' => "3"]), new Request("", "GET")], - [new Response($stream, 200), new EmptyResponse(200, ['Content-Length' => "3"]), new Request("", "HEAD")], + [HTTP::respEmpty(204), HTTP::respEmpty(204)], + [HTTP::respEmpty(401), HTTP::respEmpty(401, ['WWW-Authenticate' => "Fake Value"])], + [HTTP::respEmpty(204, ['Allow' => "PUT"]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "PUT,OPTIONS"]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => ["PUT", "OPTIONS"]]), HTTP::respEmpty(204, ['Allow' => "PUT, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => ["PUT, DELETE", "OPTIONS"]]), HTTP::respEmpty(204, ['Allow' => "PUT, DELETE, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "HEAD,GET"]), HTTP::respEmpty(204, ['Allow' => "HEAD, GET, OPTIONS"])], + [HTTP::respEmpty(204, ['Allow' => "GET"]), HTTP::respEmpty(204, ['Allow' => "GET, HEAD, OPTIONS"])], + [new TextResponse("ook", 200), new TextResponse("ook", 200, ['Content-Length' => "3"])], + [new TextResponse("", 200), new TextResponse("", 200, ['Content-Length' => "0"])], + [new TextResponse("ook", 404), new TextResponse("ook", 404, ['Content-Length' => "3"])], + [new TextResponse("", 404), new TextResponse("", 404)], + [new Response($stream, 200), new Response($stream, 200, ['Content-Length' => "3"]), new Request("", "GET")], + [new Response($stream, 200), HTTP::respEmpty(200, ['Content-Length' => "3"]), new Request("", "HEAD")], ]; } @@ -297,7 +297,7 @@ class TestREST extends \JKingWeb\Arsse\Test\AbstractTest { }); if ($called) { $hMock = $this->mock($class); - $hMock->dispatch->returns(new EmptyResponse(204)); + $hMock->dispatch->returns(HTTP::respEmpty(204)); $this->objMock->get->with($class)->returns($hMock); Arsse::$obj = $this->objMock->get(); } diff --git a/tests/cases/REST/TinyTinyRSS/TestAPI.php b/tests/cases/REST/TinyTinyRSS/TestAPI.php index 5220a69..d643491 100644 --- a/tests/cases/REST/TinyTinyRSS/TestAPI.php +++ b/tests/cases/REST/TinyTinyRSS/TestAPI.php @@ -11,6 +11,7 @@ use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Test\Result; use JKingWeb\Arsse\Misc\Date; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Context\Context; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\Transaction; @@ -18,7 +19,6 @@ use JKingWeb\Arsse\REST\TinyTinyRSS\API; use JKingWeb\Arsse\Feed\Exception as FeedException; use Psr\Http\Message\ResponseInterface; use Laminas\Diactoros\Response\JsonResponse as Response; -use Laminas\Diactoros\Response\EmptyResponse; /** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\API * @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Exception */ @@ -188,12 +188,12 @@ LONG_STRING; $this->assertMessage($exp, $this->req(null, "POST", "", "")); $this->assertMessage($exp, $this->req(null, "POST", "/", "")); $this->assertMessage($exp, $this->req(null, "POST", "/index.php", "")); - $exp = new EmptyResponse(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req(null, "POST", "/bad/path", "")); } public function testHandleOptionsRequest(): void { - $exp = new EmptyResponse(204, [ + $exp = HTTP::respEmpty(204, [ 'Allow' => "POST", 'Accept' => "application/json, text/json", ]); @@ -215,7 +215,7 @@ LONG_STRING; $this->userMock->auth->with("jane.doe@example.com", "superman")->returns(true); $this->dbMock->sessionCreate->with("john.doe@example.com")->returns("PriestsOfSyrinx", "SolarFederation"); $this->dbMock->sessionCreate->with("jane.doe@example.com")->returns("ClockworkAngels", "SevenCitiesOfGold"); - if ($sessions instanceof EmptyResponse) { + if ($sessions instanceof ResponseInterface) { $exp1 = $sessions; $exp2 = $sessions; } elseif ($sessions) { @@ -260,7 +260,7 @@ LONG_STRING; 'op' => "isLoggedIn", 'sid' => $data, ]; - if ($result instanceof EmptyResponse) { + if ($result instanceof ResponseInterface) { $exp1 = $result; $exp2 = null; } elseif ($result) { @@ -333,7 +333,7 @@ LONG_STRING; 'userHTTPAuthRequired' => true, 'userSessionEnforced' => false, ]; - $http401 = new EmptyResponse(401); + $http401 = HTTP::respEmpty(401); if ($type === "login") { return [ // conf, user, data, result @@ -532,7 +532,7 @@ LONG_STRING; 'user' => $this->userId, 'password' => "secret", ]; - $exp = new EmptyResponse(500); + $exp = HTTP::respEmpty(500); $this->assertMessage($exp, $this->req($data)); } diff --git a/tests/cases/REST/TinyTinyRSS/TestIcon.php b/tests/cases/REST/TinyTinyRSS/TestIcon.php index f541f50..ecfb992 100644 --- a/tests/cases/REST/TinyTinyRSS/TestIcon.php +++ b/tests/cases/REST/TinyTinyRSS/TestIcon.php @@ -9,10 +9,10 @@ namespace JKingWeb\Arsse\TestCase\REST\TinyTinyRSS; use JKingWeb\Arsse\Arsse; use JKingWeb\Arsse\User; use JKingWeb\Arsse\Database; +use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\REST\TinyTinyRSS\Icon; use Psr\Http\Message\ResponseInterface; -use Laminas\Diactoros\Response\EmptyResponse as Response; /** @covers \JKingWeb\Arsse\REST\TinyTinyRSS\Icon */ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { @@ -51,21 +51,21 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionIcon->with($this->anything(), 2112, false)->returns(['url' => "http://example.net/logo.png"]); $this->dbMock->subscriptionIcon->with($this->anything(), 1337, false)->returns(['url' => "http://example.org/icon.gif\r\nLocation: http://bad.example.com/"]); // these requests should succeed - $exp = new Response(301, ['Location' => "http://example.com/favicon.ico"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.com/favicon.ico"]); $this->assertMessage($exp, $this->req("42.ico")); - $exp = new Response(301, ['Location' => "http://example.net/logo.png"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.net/logo.png"]); $this->assertMessage($exp, $this->req("2112.ico")); - $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->req("1337.ico")); // these requests should fail - $exp = new Response(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->req("ook.ico")); $this->assertMessage($exp, $this->req("ook")); $this->assertMessage($exp, $this->req("47.ico")); $this->assertMessage($exp, $this->req("2112.png")); $this->assertMessage($exp, $this->req("1123.ico")); // only GET is allowed - $exp = new Response(405, ['Allow' => "GET"]); + $exp = HTTP::respEmpty(405, ['Allow' => "GET"]); $this->assertMessage($exp, $this->req("2112.ico", "PUT")); } @@ -79,32 +79,32 @@ class TestIcon extends \JKingWeb\Arsse\Test\AbstractTest { $this->dbMock->subscriptionIcon->with(null, 2112, false)->returns($url); $this->dbMock->subscriptionIcon->with(null, 1337, false)->returns($url); // these requests should succeed - $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->req("42.ico")); $this->assertMessage($exp, $this->req("2112.ico")); $this->assertMessage($exp, $this->req("1337.ico")); $this->assertMessage($exp, $this->reqAuth("42.ico")); $this->assertMessage($exp, $this->reqAuth("1337.ico")); // these requests should fail - $exp = new Response(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->reqAuth("2112.ico")); - $exp = new Response(401); + $exp = HTTP::respEmpty(401); $this->assertMessage($exp, $this->reqAuthFailed("42.ico")); $this->assertMessage($exp, $this->reqAuthFailed("1337.ico")); // with HTTP auth required, only authenticated requests should succeed self::setConf(['userHTTPAuthRequired' => true]); - $exp = new Response(301, ['Location' => "http://example.org/icon.gif"]); + $exp = HTTP::respEmpty(301, ['Location' => "http://example.org/icon.gif"]); $this->assertMessage($exp, $this->reqAuth("42.ico")); $this->assertMessage($exp, $this->reqAuth("1337.ico")); // anything else should fail - $exp = new Response(401); + $exp = HTTP::respEmpty(401); $this->assertMessage($exp, $this->req("42.ico")); $this->assertMessage($exp, $this->req("2112.ico")); $this->assertMessage($exp, $this->req("1337.ico")); $this->assertMessage($exp, $this->reqAuthFailed("42.ico")); $this->assertMessage($exp, $this->reqAuthFailed("1337.ico")); // resources for the wrtong user should still fail, too - $exp = new Response(404); + $exp = HTTP::respEmpty(404); $this->assertMessage($exp, $this->reqAuth("2112.ico")); } }