mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 21:22:40 +00:00
Implement OPTIONS requests for NCNv1; fixes #107
This commit is contained in:
parent
e1f1c8b859
commit
3d958547a5
4 changed files with 72 additions and 15 deletions
|
@ -76,6 +76,10 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
if (!Arsse::$user->authHTTP()) {
|
if (!Arsse::$user->authHTTP()) {
|
||||||
return new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.self::REALM.'"']);
|
return new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.self::REALM.'"']);
|
||||||
}
|
}
|
||||||
|
// handle HTTP OPTIONS requests
|
||||||
|
if ($req->method=="OPTIONS") {
|
||||||
|
return $this->handleHTTPOptions($req->paths);
|
||||||
|
}
|
||||||
// normalize the input
|
// normalize the input
|
||||||
if ($req->body) {
|
if ($req->body) {
|
||||||
// if the entity body is not JSON according to content type, return "415 Unsupported Media Type"
|
// if the entity body is not JSON according to content type, return "415 Unsupported Media Type"
|
||||||
|
@ -144,7 +148,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
throw new Exception405(implode(", ", array_keys($this->paths[$url])));
|
throw new Exception405(implode(", ", array_keys($this->paths[$url])));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if the path is not supported, return 501
|
// if the path is not supported, return 404
|
||||||
throw new Exception404();
|
throw new Exception404();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,6 +207,26 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
|
||||||
return $article;
|
return $article;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function handleHTTPOptions(array $url): Response {
|
||||||
|
// normalize the URL path
|
||||||
|
$url = $this->normalizePath($url);
|
||||||
|
if (isset($this->paths[$url])) {
|
||||||
|
// if the path is supported, respond with the allowed methods and other metadata
|
||||||
|
$allowed = array_keys($this->paths[$url]);
|
||||||
|
// if GET is allowed, so is HEAD
|
||||||
|
if (in_array("GET", $allowed)) {
|
||||||
|
array_unshift($allowed, "HEAD");
|
||||||
|
}
|
||||||
|
return new Response(204, "", "", [
|
||||||
|
"Allow: ".implode(",", $allowed),
|
||||||
|
"Accept: application/json",
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
// if the path is not supported, return 404
|
||||||
|
return new Response(404);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// list folders
|
// list folders
|
||||||
protected function folderList(array $url, array $data): Response {
|
protected function folderList(array $url, array $data): Response {
|
||||||
$folders = Arsse::$db->folderList(Arsse::$user->id, null, false)->getAll();
|
$folders = Arsse::$db->folderList(Arsse::$user->id, null, false)->getAll();
|
||||||
|
|
|
@ -13,21 +13,23 @@ class Versions implements \JKingWeb\Arsse\REST\Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
|
public function dispatch(\JKingWeb\Arsse\REST\Request $req): Response {
|
||||||
|
if (!preg_match("<^/?$>", $req->path)) {
|
||||||
|
// if the request path is an empty string or just a slash, the client is probably trying a version we don't support
|
||||||
|
return new Response(404);
|
||||||
|
} elseif ($req->method=="OPTIONS") {
|
||||||
|
// if the request method is OPTIONS, respond accordingly
|
||||||
|
return new Response(204, "", "", ["Allow: HEAD,GET"]);
|
||||||
|
} elseif ($req->method != "GET") {
|
||||||
// if a method other than GET was used, this is an error
|
// if a method other than GET was used, this is an error
|
||||||
if ($req->method != "GET") {
|
return new Response(405, "", "", ["Allow: HEAD,GET"]);
|
||||||
return new Response(405, "", "", ["Allow: GET"]);
|
} else {
|
||||||
}
|
// otherwise return the supported versions
|
||||||
if (preg_match("<^/?$>", $req->path)) {
|
|
||||||
// if the request path is an empty string or just a slash, return the supported versions
|
|
||||||
$out = [
|
$out = [
|
||||||
'apiLevels' => [
|
'apiLevels' => [
|
||||||
'v1-2',
|
'v1-2',
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
return new Response(200, $out);
|
return new Response(200, $out);
|
||||||
} else {
|
|
||||||
// if the URL path was anything else, the client is probably trying a version we don't support
|
|
||||||
return new Response(404);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -311,6 +311,12 @@ class TestNCNV1_2 extends Test\AbstractTest {
|
||||||
$this->clearData();
|
$this->clearData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSendAuthenticationChallenge() {
|
||||||
|
Phake::when(Arsse::$user)->authHTTP->thenReturn(false);
|
||||||
|
$exp = new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.REST\NextCloudNews\V1_2::REALM.'"']);
|
||||||
|
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/")));
|
||||||
|
}
|
||||||
|
|
||||||
public function testRespondToInvalidPaths() {
|
public function testRespondToInvalidPaths() {
|
||||||
$errs = [
|
$errs = [
|
||||||
404 => [
|
404 => [
|
||||||
|
@ -364,10 +370,24 @@ class TestNCNV1_2 extends Test\AbstractTest {
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '<data/>', 'application/json')));
|
$this->assertEquals($exp, $this->h->dispatch(new Request("PUT", "/folders/1", '<data/>', 'application/json')));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSendAuthenticationChallenge() {
|
public function testRespondToOptionsRequests() {
|
||||||
Phake::when(Arsse::$user)->authHTTP->thenReturn(false);
|
$exp = new Response(204, "", "", [
|
||||||
$exp = new Response(401, "", "", ['WWW-Authenticate: Basic realm="'.REST\NextCloudNews\V1_2::REALM.'"']);
|
"Allow: HEAD,GET,POST",
|
||||||
$this->assertEquals($exp, $this->h->dispatch(new Request("GET", "/")));
|
"Accept: application/json",
|
||||||
|
]);
|
||||||
|
$this->assertEquals($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds")));
|
||||||
|
$exp = new Response(204, "", "", [
|
||||||
|
"Allow: DELETE",
|
||||||
|
"Accept: application/json",
|
||||||
|
]);
|
||||||
|
$this->assertEquals($exp, $this->h->dispatch(new Request("OPTIONS", "/feeds/2112")));
|
||||||
|
$exp = new Response(204, "", "", [
|
||||||
|
"Allow: HEAD,GET",
|
||||||
|
"Accept: application/json",
|
||||||
|
]);
|
||||||
|
$this->assertEquals($exp, $this->h->dispatch(new Request("OPTIONS", "/user")));
|
||||||
|
$exp = new Response(404);
|
||||||
|
$this->assertEquals($exp, $this->h->dispatch(new Request("OPTIONS", "/invalid/path")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testListFolders() {
|
public function testListFolders() {
|
||||||
|
|
|
@ -29,8 +29,16 @@ class TestNCNVersionDiscovery extends Test\AbstractTest {
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertEquals($exp, $res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testRespondToOptionsRequest() {
|
||||||
|
$exp = new Response(204, "", "", ["Allow: HEAD,GET"]);
|
||||||
|
$h = new REST\NextCloudNews\Versions();
|
||||||
|
$req = new Request("OPTIONS", "/");
|
||||||
|
$res = $h->dispatch($req);
|
||||||
|
$this->assertEquals($exp, $res);
|
||||||
|
}
|
||||||
|
|
||||||
public function testUseIncorrectMethod() {
|
public function testUseIncorrectMethod() {
|
||||||
$exp = new Response(405, "", "", ["Allow: GET"]);
|
$exp = new Response(405, "", "", ["Allow: HEAD,GET"]);
|
||||||
$h = new REST\NextCloudNews\Versions();
|
$h = new REST\NextCloudNews\Versions();
|
||||||
$req = new Request("POST", "/");
|
$req = new Request("POST", "/");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
|
@ -43,5 +51,8 @@ class TestNCNVersionDiscovery extends Test\AbstractTest {
|
||||||
$req = new Request("GET", "/ook");
|
$req = new Request("GET", "/ook");
|
||||||
$res = $h->dispatch($req);
|
$res = $h->dispatch($req);
|
||||||
$this->assertEquals($exp, $res);
|
$this->assertEquals($exp, $res);
|
||||||
|
$req = new Request("OPTIONS", "/ook");
|
||||||
|
$res = $h->dispatch($req);
|
||||||
|
$this->assertEquals($exp, $res);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue