diff --git a/config/autoload/middleware-pipeline.global.php b/config/autoload/middleware-pipeline.global.php index b83ee2e7..1deff0fa 100644 --- a/config/autoload/middleware-pipeline.global.php +++ b/config/autoload/middleware-pipeline.global.php @@ -9,6 +9,7 @@ use Mezzio\Helper; use Mezzio\ProblemDetails; use Mezzio\Router; use PhpMiddleware\RequestId\RequestIdMiddleware; +use RKA\Middleware\IpAddress; return [ @@ -64,6 +65,8 @@ return [ ], 'not-found' => [ 'middleware' => [ + // This middleware is in front of tracking actions explicitly. Putting here for orphan visits tracking + IpAddress::class, Core\ErrorHandler\NotFoundTypeResolverMiddleware::class, Core\ErrorHandler\NotFoundTrackerMiddleware::class, Core\ErrorHandler\NotFoundRedirectHandler::class, diff --git a/module/Core/src/ErrorHandler/NotFoundTemplateHandler.php b/module/Core/src/ErrorHandler/NotFoundTemplateHandler.php index 62b78973..61d67403 100644 --- a/module/Core/src/ErrorHandler/NotFoundTemplateHandler.php +++ b/module/Core/src/ErrorHandler/NotFoundTemplateHandler.php @@ -7,10 +7,10 @@ namespace Shlinkio\Shlink\Core\ErrorHandler; use Closure; use Fig\Http\Message\StatusCodeInterface; use Laminas\Diactoros\Response; -use Mezzio\Router\RouteResult; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; +use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType; use function file_get_contents; use function sprintf; @@ -29,11 +29,11 @@ class NotFoundTemplateHandler implements RequestHandlerInterface public function handle(ServerRequestInterface $request): ResponseInterface { - /** @var RouteResult $routeResult */ - $routeResult = $request->getAttribute(RouteResult::class) ?? RouteResult::fromRouteFailure(null); + /** @var NotFoundType $notFoundType */ + $notFoundType = $request->getAttribute(NotFoundType::class); $status = StatusCodeInterface::STATUS_NOT_FOUND; - $template = $routeResult->isFailure() ? self::NOT_FOUND_TEMPLATE : self::INVALID_SHORT_CODE_TEMPLATE; + $template = $notFoundType->isInvalidShortUrl() ? self::INVALID_SHORT_CODE_TEMPLATE : self::NOT_FOUND_TEMPLATE; $templateContent = ($this->readFile)(sprintf('%s/%s', self::TEMPLATES_BASE_DIR, $template)); return new Response\HtmlResponse($templateContent, $status); } diff --git a/module/Core/test/ErrorHandler/NotFoundTemplateHandlerTest.php b/module/Core/test/ErrorHandler/NotFoundTemplateHandlerTest.php index 6b9f9989..b5c80de4 100644 --- a/module/Core/test/ErrorHandler/NotFoundTemplateHandlerTest.php +++ b/module/Core/test/ErrorHandler/NotFoundTemplateHandlerTest.php @@ -7,27 +7,29 @@ namespace ShlinkioTest\Shlink\Core\ErrorHandler; use Closure; use Laminas\Diactoros\Response; use Laminas\Diactoros\ServerRequestFactory; +use Laminas\Diactoros\Uri; use Mezzio\Router\Route; use Mezzio\Router\RouteResult; use PHPUnit\Framework\TestCase; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; +use Shlinkio\Shlink\Core\Action\RedirectAction; +use Shlinkio\Shlink\Core\ErrorHandler\Model\NotFoundType; use Shlinkio\Shlink\Core\ErrorHandler\NotFoundTemplateHandler; class NotFoundTemplateHandlerTest extends TestCase { private NotFoundTemplateHandler $handler; - private Closure $readFile; private bool $readFileCalled; public function setUp(): void { $this->readFileCalled = false; - $this->readFile = function (string $fileName): string { + $readFile = function (string $fileName): string { $this->readFileCalled = true; return $fileName; }; - $this->handler = new NotFoundTemplateHandler($this->readFile); + $this->handler = new NotFoundTemplateHandler($readFile); } /** @@ -45,15 +47,29 @@ class NotFoundTemplateHandlerTest extends TestCase public function provideTemplates(): iterable { - $request = ServerRequestFactory::fromGlobals(); + $request = ServerRequestFactory::fromGlobals()->withUri(new Uri('/foo')); - yield [$request, NotFoundTemplateHandler::NOT_FOUND_TEMPLATE]; - yield [ - $request->withAttribute( + yield 'base url' => [$this->withNotFoundType($request, '/foo'), NotFoundTemplateHandler::NOT_FOUND_TEMPLATE]; + yield 'regular not found' => [$this->withNotFoundType($request), NotFoundTemplateHandler::NOT_FOUND_TEMPLATE]; + yield 'invalid short code' => [ + $this->withNotFoundType($request->withAttribute( RouteResult::class, - RouteResult::fromRoute(new Route('', $this->prophesize(MiddlewareInterface::class)->reveal())), - ), + RouteResult::fromRoute( + new Route( + '', + $this->prophesize(MiddlewareInterface::class)->reveal(), + ['GET'], + RedirectAction::class, + ), + ), + )), NotFoundTemplateHandler::INVALID_SHORT_CODE_TEMPLATE, ]; } + + private function withNotFoundType(ServerRequestInterface $req, string $baseUrl = ''): ServerRequestInterface + { + $type = NotFoundType::fromRequest($req, $baseUrl); + return $req->withAttribute(NotFoundType::class, $type); + } }