Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions examples/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@
});
$app->get('/error/class', 'Acme\Http\UnknownDeleteUserController'); // @phpstan-ignore-line

// OPTIONS *
$app->options('', function () {
$app->options('*', function () {
return new React\Http\Message\Response(200);
});

Expand Down
5 changes: 5 additions & 0 deletions src/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ public function delete(string $route, $handler, ...$handlers): void
*/
public function options(string $route, $handler, ...$handlers): void
{
// backward compatibility: `OPTIONS * HTTP/1.1` can be matched with empty path (legacy)
if ($route === '') {
$route = '*';
}

$this->map(['OPTIONS'], $route, $handler, ...$handlers);
}

Expand Down
7 changes: 5 additions & 2 deletions src/Io/RouteHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,18 @@ public function map(array $methods, string $route, $handler, ...$handlers): void
*/
public function __invoke(ServerRequestInterface $request)
{
if ($request->getRequestTarget()[0] !== '/' && $request->getRequestTarget() !== '*') {
$target = $request->getRequestTarget();
if ($target[0] !== '/' && $target !== '*') {
return $this->errorHandler->requestProxyUnsupported();
} elseif ($target !== '*') {
$target = $request->getUri()->getPath();
}

if ($this->routeDispatcher === null) {
$this->routeDispatcher = new RouteDispatcher($this->routeCollector->getData());
}

$routeInfo = $this->routeDispatcher->dispatch($request->getMethod(), $request->getUri()->getPath());
$routeInfo = $this->routeDispatcher->dispatch($request->getMethod(), $target);
assert(\is_array($routeInfo) && isset($routeInfo[0]));

// happy path: matching route found, assign route attributes and invoke request handler
Expand Down
31 changes: 30 additions & 1 deletion tests/AppTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -973,7 +973,36 @@ public function testHandleRequestWithMatchingRouteReturnsResponseFromMatchingRou
$this->assertEquals("OK\n", (string) $response->getBody());
}

public function testHandleRequestWithOptionsAsteriskRequestReturnsResponseFromMatchingEmptyRouteHandler(): void
public function testHandleRequestWithOptionsAsteriskRequestReturnsResponseFromMatchingAsteriskRouteHandler(): void
{
$app = $this->createAppWithoutLogger();

$app->options('*', function () {
return new Response(
200,
[
'Content-Type' => 'text/html'
],
"OK\n"
);
});

$request = new ServerRequest('OPTIONS', 'http://localhost');
$request = $request->withRequestTarget('*');

// $response = $app->handleRequest($request);
$ref = new ReflectionMethod($app, 'handleRequest');
$ref->setAccessible(true);
$response = $ref->invoke($app, $request);

/** @var ResponseInterface $response */
$this->assertInstanceOf(ResponseInterface::class, $response);
$this->assertEquals(200, $response->getStatusCode());
$this->assertEquals('text/html', $response->getHeaderLine('Content-Type'));
$this->assertEquals("OK\n", (string) $response->getBody());
}

public function testHandleRequestWithOptionsAsteriskRequestReturnsResponseFromMatchingDeprecatedEmptyRouteHandler(): void
{
$app = $this->createAppWithoutLogger();

Expand Down
4 changes: 2 additions & 2 deletions tests/Io/RouteHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -332,14 +332,14 @@ public function testHandleRequestWithGetRequestWithHttpUrlInPathReturnsResponseF
$this->assertSame($response, $ret);
}

public function testHandleRequestWithOptionsAsteriskRequestReturnsResponseFromMatchingEmptyHandler(): void
public function testHandleRequestWithOptionsAsteriskRequestReturnsResponseFromMatchingAsteriskHandler(): void
{
$request = new ServerRequest('OPTIONS', 'http://example.com');
$request = $request->withRequestTarget('*');
$response = new Response(200, [], '');

$handler = new RouteHandler();
$handler->map(['OPTIONS'], '', function () use ($response) { return $response; });
$handler->map(['OPTIONS'], '*', function () use ($response) { return $response; });

$ret = $handler($request);

Expand Down