diff --git a/config/autoload/redirects.global.php b/config/autoload/redirects.global.php index 426bb2ac..26a3c032 100644 --- a/config/autoload/redirects.global.php +++ b/config/autoload/redirects.global.php @@ -16,7 +16,7 @@ return [ ], 'redirects' => [ - 'redirect_status_code' => (int) EnvVars::REDIRECT_STATUS_CODE->loadFromEnv(DEFAULT_REDIRECT_STATUS_CODE), + 'redirect_status_code' => (int) EnvVars::REDIRECT_STATUS_CODE->loadFromEnv(DEFAULT_REDIRECT_STATUS_CODE->value), 'redirect_cache_lifetime' => (int) EnvVars::REDIRECT_CACHE_LIFETIME->loadFromEnv( DEFAULT_REDIRECT_CACHE_LIFETIME, ), diff --git a/config/constants.php b/config/constants.php index d3d869c3..f6d5e9aa 100644 --- a/config/constants.php +++ b/config/constants.php @@ -4,12 +4,12 @@ declare(strict_types=1); namespace Shlinkio\Shlink; -use Fig\Http\Message\StatusCodeInterface; +use Shlinkio\Shlink\Core\Util\RedirectStatus; const DEFAULT_DELETE_SHORT_URL_THRESHOLD = 15; const DEFAULT_SHORT_CODES_LENGTH = 5; const MIN_SHORT_CODES_LENGTH = 4; -const DEFAULT_REDIRECT_STATUS_CODE = StatusCodeInterface::STATUS_FOUND; +const DEFAULT_REDIRECT_STATUS_CODE = RedirectStatus::STATUS_302; const DEFAULT_REDIRECT_CACHE_LIFETIME = 30; const LOCAL_LOCK_FACTORY = 'Shlinkio\Shlink\LocalLockFactory'; const TITLE_TAG_VALUE = '/]*>(.*?)<\/title>/i'; // Matches the value inside a html title tag diff --git a/module/Core/src/Options/RedirectOptions.php b/module/Core/src/Options/RedirectOptions.php index 9a1fedac..dd9f0a6d 100644 --- a/module/Core/src/Options/RedirectOptions.php +++ b/module/Core/src/Options/RedirectOptions.php @@ -4,23 +4,22 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Core\Options; -use function Functional\contains; +use Fig\Http\Message\StatusCodeInterface; +use Shlinkio\Shlink\Core\Util\RedirectStatus; use const Shlinkio\Shlink\DEFAULT_REDIRECT_CACHE_LIFETIME; use const Shlinkio\Shlink\DEFAULT_REDIRECT_STATUS_CODE; final class RedirectOptions { - public readonly int $redirectStatusCode; + public readonly RedirectStatus $redirectStatusCode; public readonly int $redirectCacheLifetime; public function __construct( - int $redirectStatusCode = DEFAULT_REDIRECT_STATUS_CODE, + int $redirectStatusCode = StatusCodeInterface::STATUS_FOUND, int $redirectCacheLifetime = DEFAULT_REDIRECT_CACHE_LIFETIME, ) { - $this->redirectStatusCode = contains([301, 302], $redirectStatusCode) - ? $redirectStatusCode - : DEFAULT_REDIRECT_STATUS_CODE; + $this->redirectStatusCode = RedirectStatus::tryFrom($redirectStatusCode) ?? DEFAULT_REDIRECT_STATUS_CODE; $this->redirectCacheLifetime = $redirectCacheLifetime > 0 ? $redirectCacheLifetime : DEFAULT_REDIRECT_CACHE_LIFETIME; diff --git a/module/Core/src/Util/RedirectResponseHelper.php b/module/Core/src/Util/RedirectResponseHelper.php index dfc87480..01e581a7 100644 --- a/module/Core/src/Util/RedirectResponseHelper.php +++ b/module/Core/src/Util/RedirectResponseHelper.php @@ -4,7 +4,6 @@ declare(strict_types=1); namespace Shlinkio\Shlink\Core\Util; -use Fig\Http\Message\StatusCodeInterface; use Laminas\Diactoros\Response\RedirectResponse; use Psr\Http\Message\ResponseInterface; use Shlinkio\Shlink\Core\Options\RedirectOptions; @@ -13,17 +12,17 @@ use function sprintf; class RedirectResponseHelper implements RedirectResponseHelperInterface { - public function __construct(private RedirectOptions $options) + public function __construct(private readonly RedirectOptions $options) { } public function buildRedirectResponse(string $location): ResponseInterface { $statusCode = $this->options->redirectStatusCode; - $headers = $statusCode === StatusCodeInterface::STATUS_FOUND ? [] : [ + $headers = ! $statusCode->allowsCache() ? [] : [ 'Cache-Control' => sprintf('private,max-age=%s', $this->options->redirectCacheLifetime), ]; - return new RedirectResponse($location, $statusCode, $headers); + return new RedirectResponse($location, $statusCode->value, $headers); } } diff --git a/module/Core/src/Util/RedirectStatus.php b/module/Core/src/Util/RedirectStatus.php new file mode 100644 index 00000000..d14e4fea --- /dev/null +++ b/module/Core/src/Util/RedirectStatus.php @@ -0,0 +1,20 @@ + [302, 20, 302, null]; - yield 'status over 302' => [400, 20, 302, null]; + yield 'status 307' => [307, 20, 307, null]; + yield 'status over 308' => [400, 20, 302, null]; yield 'status below 301' => [201, 20, 302, null]; yield 'status 301 with valid expiration' => [301, 20, 301, 'private,max-age=20']; yield 'status 301 with zero expiration' => [301, 0, 301, 'private,max-age=30']; yield 'status 301 with negative expiration' => [301, -20, 301, 'private,max-age=30']; + yield 'status 308 with valid expiration' => [308, 20, 308, 'private,max-age=20']; + yield 'status 308 with zero expiration' => [308, 0, 308, 'private,max-age=30']; + yield 'status 308 with negative expiration' => [308, -20, 308, 'private,max-age=30']; } private function helper(?RedirectOptions $options = null): RedirectResponseHelper