1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-22 21:22:40 +00:00

Simplify handling of invalid paths and methods

This commit is contained in:
J. King 2020-12-01 11:06:29 -05:00
parent def07bb1ad
commit 7fa5523a7d
5 changed files with 22 additions and 62 deletions

View file

@ -1,10 +0,0 @@
<?php
/** @license MIT
* Copyright 2017 J. King, Dustin Wilson et al.
* See LICENSE and AUTHORS files for details */
declare(strict_types=1);
namespace JKingWeb\Arsse\REST;
class Exception404 extends \Exception {
}

View file

@ -1,10 +0,0 @@
<?php
/** @license MIT
* Copyright 2017 J. King, Dustin Wilson et al.
* See LICENSE and AUTHORS files for details */
declare(strict_types=1);
namespace JKingWeb\Arsse\REST;
class Exception405 extends \Exception {
}

View file

@ -12,9 +12,6 @@ use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\HTTP;
use JKingWeb\Arsse\Misc\ValueInfo; use JKingWeb\Arsse\Misc\ValueInfo;
use JKingWeb\Arsse\REST\Exception; use JKingWeb\Arsse\REST\Exception;
use JKingWeb\Arsse\REST\Exception404;
use JKingWeb\Arsse\REST\Exception405;
use JKingWeb\Arsse\REST\Exception501;
use JKingWeb\Arsse\User\ExceptionConflict as UserException; use JKingWeb\Arsse\User\ExceptionConflict as UserException;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
@ -86,6 +83,9 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
return $this->handleHTTPOptions($target); return $this->handleHTTPOptions($target);
} }
$func = $this->chooseCall($target, $method); $func = $this->chooseCall($target, $method);
if ($func instanceof ResponseInterface) {
return $func;
}
if ($func === "opmlImport") { if ($func === "opmlImport") {
if (!HTTP::matchType($req, "", ...[self::ACCEPTED_TYPES_OPML])) { if (!HTTP::matchType($req, "", ...[self::ACCEPTED_TYPES_OPML])) {
return new ErrorResponse("", 415, ['Accept' => implode(", ", self::ACCEPTED_TYPES_OPML)]); return new ErrorResponse("", 415, ['Accept' => implode(", ", self::ACCEPTED_TYPES_OPML)]);
@ -149,7 +149,7 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
} }
} }
protected function chooseCall(string $url, string $method): string { protected function chooseCall(string $url, string $method) {
// // normalize the URL path: change any IDs to 1 for easier comparison // // normalize the URL path: change any IDs to 1 for easier comparison
$url = $this->normalizePathIds($url); $url = $this->normalizePathIds($url);
// normalize the HTTP method to uppercase // normalize the HTTP method to uppercase
@ -160,18 +160,15 @@ class V1 extends \JKingWeb\Arsse\REST\AbstractHandler {
// if the path is supported, make sure the method is allowed // if the path is supported, make sure the method is allowed
if (isset($this->paths[$url][$method])) { if (isset($this->paths[$url][$method])) {
// if it is allowed, return the object method to run, assuming the method exists // if it is allowed, return the object method to run, assuming the method exists
if (method_exists($this, $this->paths[$url][$method])) { assert(method_exists($this, $this->paths[$url][$method]), new \Exception("Method is not implemented"));
return $this->paths[$url][$method]; return $this->paths[$url][$method];
} else {
throw new Exception501(); // @codeCoverageIgnore
}
} else { } else {
// otherwise return 405 // otherwise return 405
throw new Exception405(implode(", ", array_keys($this->paths[$url]))); return new EmptyResponse(405, ['Allow' => implode(", ", array_keys($this->paths[$url]))]);
} }
} else { } else {
// if the path is not supported, return 404 // if the path is not supported, return 404
throw new Exception404(); return new EmptyResponse(404);
} }
} }

View file

@ -15,9 +15,6 @@ use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\Feed\Exception as FeedException; use JKingWeb\Arsse\Feed\Exception as FeedException;
use JKingWeb\Arsse\Misc\HTTP; use JKingWeb\Arsse\Misc\HTTP;
use JKingWeb\Arsse\REST\Exception; use JKingWeb\Arsse\REST\Exception;
use JKingWeb\Arsse\REST\Exception404;
use JKingWeb\Arsse\REST\Exception405;
use JKingWeb\Arsse\REST\Exception501;
use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
use Laminas\Diactoros\Response\JsonResponse as Response; use Laminas\Diactoros\Response\JsonResponse as Response;
@ -110,15 +107,14 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// merge GET and POST data, and normalize it. POST parameters are preferred over GET parameters // merge GET and POST data, and normalize it. POST parameters are preferred over GET parameters
$data = $this->normalizeInput(array_merge($req->getQueryParams(), $data), $this->validInput, "unix"); $data = $this->normalizeInput(array_merge($req->getQueryParams(), $data), $this->validInput, "unix");
// check to make sure the requested function is implemented // check to make sure the requested function is implemented
$func = $this->chooseCall($target, $req->getMethod());
if ($func instanceof ResponseInterface) {
return $func;
}
// dispatch // dispatch
try { try {
$func = $this->chooseCall($target, $req->getMethod());
$path = explode("/", ltrim($target, "/")); $path = explode("/", ltrim($target, "/"));
return $this->$func($path, $data); return $this->$func($path, $data);
} catch (Exception404 $e) {
return new EmptyResponse(404);
} catch (Exception405 $e) {
return new EmptyResponse(405, ['Allow' => $e->getMessage()]);
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
} catch (Exception $e) { } catch (Exception $e) {
// if there was a REST exception return 400 // if there was a REST exception return 400
@ -141,7 +137,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
return implode("/", $path); return implode("/", $path);
} }
protected function chooseCall(string $url, string $method): string { protected function chooseCall(string $url, string $method) {
// // normalize the URL path: change any IDs to 1 for easier comparison // // normalize the URL path: change any IDs to 1 for easier comparison
$url = $this->normalizePathIds($url); $url = $this->normalizePathIds($url);
// normalize the HTTP method to uppercase // normalize the HTTP method to uppercase
@ -152,18 +148,15 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// if the path is supported, make sure the method is allowed // if the path is supported, make sure the method is allowed
if (isset($this->paths[$url][$method])) { if (isset($this->paths[$url][$method])) {
// if it is allowed, return the object method to run, assuming the method exists // if it is allowed, return the object method to run, assuming the method exists
if (method_exists($this, $this->paths[$url][$method])) { assert(method_exists($this, $this->paths[$url][$method]), new \Exception("Method is not implemented"));
return $this->paths[$url][$method]; return $this->paths[$url][$method];
} else {
throw new Exception501(); // @codeCoverageIgnore
}
} else { } else {
// otherwise return 405 // otherwise return 405
throw new Exception405(implode(", ", array_keys($this->paths[$url]))); return new EmptyResponse(405, ['Allow' => implode(", ", array_keys($this->paths[$url]))]);
} }
} else { } else {
// if the path is not supported, return 404 // if the path is not supported, return 404
throw new Exception404(); return new EmptyResponse(404);
} }
} }

View file

@ -11,7 +11,6 @@ use JKingWeb\Arsse\User;
use JKingWeb\Arsse\Database; use JKingWeb\Arsse\Database;
use JKingWeb\Arsse\Db\Transaction; use JKingWeb\Arsse\Db\Transaction;
use JKingWeb\Arsse\Db\ExceptionInput; use JKingWeb\Arsse\Db\ExceptionInput;
use JKingWeb\Arsse\REST\Exception404;
use JKingWeb\Arsse\REST\Miniflux\V1; use JKingWeb\Arsse\REST\Miniflux\V1;
use JKingWeb\Arsse\REST\Miniflux\ErrorResponse; use JKingWeb\Arsse\REST\Miniflux\ErrorResponse;
use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ResponseInterface;
@ -61,7 +60,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
/** @dataProvider provideAuthResponses */ /** @dataProvider provideAuthResponses */
public function testAuthenticateAUser($token, bool $auth, bool $success): void { public function testAuthenticateAUser($token, bool $auth, bool $success): void {
$exp = new ErrorResponse("401", 401); $exp = $success ? new EmptyResponse(404) : new ErrorResponse("401", 401);
$user = "john.doe@example.com"; $user = "john.doe@example.com";
if ($token !== null) { if ($token !== null) {
$headers = ['X-Auth-Token' => $token]; $headers = ['X-Auth-Token' => $token];
@ -71,17 +70,8 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
Arsse::$user->id = null; Arsse::$user->id = null;
\Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("subjectMissing")); \Phake::when(Arsse::$db)->tokenLookup->thenThrow(new ExceptionInput("subjectMissing"));
\Phake::when(Arsse::$db)->tokenLookup("miniflux.login", $this->token)->thenReturn(['user' => $user]); \Phake::when(Arsse::$db)->tokenLookup("miniflux.login", $this->token)->thenReturn(['user' => $user]);
if ($success) {
$this->expectExceptionObject(new Exception404);
try {
$this->req("GET", "/", "", $headers, $auth);
} finally {
$this->assertSame($user, Arsse::$user->id);
}
} else {
$this->assertMessage($exp, $this->req("GET", "/", "", $headers, $auth)); $this->assertMessage($exp, $this->req("GET", "/", "", $headers, $auth));
$this->assertNull(Arsse::$user->id); $this->assertSame($success ? $user : null, Arsse::$user->id);
}
} }
public function provideAuthResponses(): iterable { public function provideAuthResponses(): iterable {
@ -100,7 +90,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
} }
/** @dataProvider provideInvalidPaths */ /** @dataProvider provideInvalidPaths */
public function xtestRespondToInvalidPaths($path, $method, $code, $allow = null): void { public function testRespondToInvalidPaths($path, $method, $code, $allow = null): void {
$exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []); $exp = new EmptyResponse($code, $allow ? ['Allow' => $allow] : []);
$this->assertMessage($exp, $this->req($method, $path)); $this->assertMessage($exp, $this->req($method, $path));
} }
@ -108,7 +98,7 @@ class TestV1 extends \JKingWeb\Arsse\Test\AbstractTest {
public function provideInvalidPaths(): array { public function provideInvalidPaths(): array {
return [ return [
["/", "GET", 404], ["/", "GET", 404],
["/version", "POST", 405, "GET"], ["/me", "POST", 405, "GET"],
]; ];
} }