Skip to content

Commit

Permalink
Add auto response for OPTIONS method in same origin
Browse files Browse the repository at this point in the history
  • Loading branch information
rustamwin committed Oct 21, 2021
1 parent 4108045 commit f221fd4
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 4 deletions.
28 changes: 26 additions & 2 deletions src/Middleware/Router.php
Expand Up @@ -9,6 +9,7 @@
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Yiisoft\Http\Method;
use Yiisoft\Http\Status;
use Yiisoft\Middleware\Dispatcher\MiddlewareDispatcher;
use Yiisoft\Router\CurrentRoute;
Expand All @@ -20,9 +21,14 @@ final class Router implements MiddlewareInterface
private ResponseFactoryInterface $responseFactory;
private MiddlewareDispatcher $dispatcher;
private CurrentRoute $currentRoute;
private ?bool $autoResponseOptions = true;

public function __construct(UrlMatcherInterface $matcher, ResponseFactoryInterface $responseFactory, MiddlewareDispatcher $dispatcher, CurrentRoute $currentRoute)
{
public function __construct(
UrlMatcherInterface $matcher,
ResponseFactoryInterface $responseFactory,
MiddlewareDispatcher $dispatcher,
CurrentRoute $currentRoute
) {
$this->matcher = $matcher;
$this->responseFactory = $responseFactory;
$this->dispatcher = $dispatcher;
Expand All @@ -36,6 +42,10 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
$this->currentRoute->setUri($request->getUri());

if ($result->isMethodFailure()) {
if ($this->autoResponseOptions && $request->getMethod() === Method::OPTIONS) {
return $this->responseFactory->createResponse(Status::NO_CONTENT)
->withHeader('Allow', implode(', ', $result->methods()));
}
return $this->responseFactory->createResponse(Status::METHOD_NOT_ALLOWED)
->withHeader('Allow', implode(', ', $result->methods()));
}
Expand All @@ -52,4 +62,18 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface

return $result->withDispatcher($this->dispatcher)->process($request, $handler);
}

public function withAutoResponseOptions(): self
{
$new = clone $this;
$new->autoResponseOptions = true;
return $new;
}

public function withoutAutoResponseOptions(): self
{
$new = clone $this;
$new->autoResponseOptions = false;
return $new;
}
}
44 changes: 42 additions & 2 deletions tests/Middleware/RouterTest.php
Expand Up @@ -35,11 +35,23 @@ private function createRouterMiddleware(?CurrentRoute $currentRoute = null): Rou
return new Router($this->getMatcher(), new Psr17Factory(), $dispatcher, $currentRoute ?? new CurrentRoute());
}

private function processWithRouter(ServerRequestInterface $request, ?CurrentRoute $currentRoute = null): ResponseInterface
{
private function processWithRouter(
ServerRequestInterface $request,
?CurrentRoute $currentRoute = null
): ResponseInterface {
return $this->createRouterMiddleware($currentRoute)->process($request, $this->createRequestHandler());
}

private function processWithRouterWithoutAutoResponse(
ServerRequestInterface $request,
?CurrentRoute $currentRoute = null
): ResponseInterface {
return $this->createRouterMiddleware($currentRoute)->withoutAutoResponseOptions()->process(
$request,
$this->createRequestHandler()
);
}

public function testProcessSuccess(): void
{
$request = new ServerRequest('GET', '/');
Expand All @@ -62,6 +74,29 @@ public function testMethodMismatchRespondWith405(): void
$this->assertSame('GET, HEAD', $response->getHeaderLine('Allow'));
}

public function testAutoResponseOptions(): void
{
$request = new ServerRequest('OPTIONS', '/');
$response = $this->processWithRouter($request);
$this->assertSame(204, $response->getStatusCode());
$this->assertSame('GET, HEAD', $response->getHeaderLine('Allow'));
}

public function testWithOptionsHandler(): void
{
$request = new ServerRequest('OPTIONS', '/options');
$response = $this->processWithRouter($request);
$this->assertSame(201, $response->getStatusCode());
}

public function testWithoutAutoResponseOptions(): void
{
$request = new ServerRequest('OPTIONS', '/');
$response = $this->processWithRouterWithoutAutoResponse($request);
$this->assertSame(405, $response->getStatusCode());
$this->assertSame('GET, HEAD', $response->getHeaderLine('Allow'));
}

public function testGetCurrentRoute(): void
{
$currentRoute = new CurrentRoute();
Expand Down Expand Up @@ -104,6 +139,11 @@ public function __construct($middleware)
*/
public function match(ServerRequestInterface $request): MatchingResult
{
if ($request->getMethod() === 'OPTIONS' && $request->getUri()->getPath() === '/options') {
$route = Route::methods(['OPTIONS'], '/options')->middleware($this->middleware);
return MatchingResult::fromSuccess($route, ['method' => 'options']);
}

if ($request->getUri()->getPath() !== '/') {
return MatchingResult::fromFailure(Method::ALL);
}
Expand Down

0 comments on commit f221fd4

Please sign in to comment.