From bff262ffb23f5789a3238c616335a5a5c0cfc828 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 25 Feb 2026 02:54:17 +0800 Subject: [PATCH 1/2] add failing test --- tests/system/Test/FeatureTestTraitTest.php | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/system/Test/FeatureTestTraitTest.php b/tests/system/Test/FeatureTestTraitTest.php index 870572174204..a5472ddd969d 100644 --- a/tests/system/Test/FeatureTestTraitTest.php +++ b/tests/system/Test/FeatureTestTraitTest.php @@ -16,6 +16,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Events\Events; use CodeIgniter\Exceptions\PageNotFoundException; +use CodeIgniter\Exceptions\RuntimeException; use CodeIgniter\HTTP\Method; use CodeIgniter\HTTP\Response; use CodeIgniter\Test\Mock\MockCodeIgniter; @@ -689,4 +690,33 @@ public function testForceGlobalSecureRequests(): void // Do not redirect. $response->assertStatus(200); } + + #[DataProvider('provideWithRoutesWithInvalidMethod')] + public function testWithRoutesWithInvalidMethod(string $method): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage(sprintf('Invalid HTTP method "%s" provided for route "home".', $method)); + + $this->withRoutes([ + [ + $method, + 'home', + static fn (): string => 'Hello World', + ], + ]); + } + + /** + * @return iterable + */ + public static function provideWithRoutesWithInvalidMethod(): iterable + { + foreach (['ADD', 'CLI', ...Method::all()] as $method) { + yield "wrong {$method}" => [$method . 'S']; + } + + yield 'route collection addRedirect' => ['addRedirect']; + + yield 'route collection setHTTPVerb' => ['setHTTPVerb']; + } } From 31c3bc6d984e2ae8d6e1816f849b4dcbfd7b29dd Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 25 Feb 2026 03:49:42 +0800 Subject: [PATCH 2/2] add fix and changelog --- system/HTTP/Method.php | 2 +- system/Test/FeatureTestTrait.php | 16 +++++++++++----- user_guide_src/source/changelogs/v4.7.1.rst | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/system/HTTP/Method.php b/system/HTTP/Method.php index ee3a09ec4b0d..09e1dbc95ecb 100644 --- a/system/HTTP/Method.php +++ b/system/HTTP/Method.php @@ -102,7 +102,7 @@ class Method /** * Returns all HTTP methods. * - * @return list + * @return list */ public static function all(): array { diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index 618a2bcdb485..a271191a2271 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -15,6 +15,7 @@ use Closure; use CodeIgniter\Events\Events; +use CodeIgniter\Exceptions\RuntimeException; use CodeIgniter\HTTP\Exceptions\RedirectException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Method; @@ -76,11 +77,16 @@ protected function withRoutes(?array $routes = null) ); } - /** - * @TODO For backward compatibility. Remove strtolower() in the future. - * @deprecated 4.5.0 - */ - $method = strtolower($route[0]); + // @todo v4.7.1 Remove the strtoupper() and use 'add' in v4.8.0 + if (! in_array(strtoupper($route[0]), ['ADD', 'CLI', ...Method::all()], true)) { + throw new RuntimeException(sprintf( + 'Invalid HTTP method "%s" provided for route "%s".', + $route[0], + $route[1], + )); + } + + $method = strtolower($route[0]); // convert to method of RouteCollection if (isset($route[3])) { $collection->{$method}($route[1], $route[2], $route[3]); diff --git a/user_guide_src/source/changelogs/v4.7.1.rst b/user_guide_src/source/changelogs/v4.7.1.rst index 4eeceecdb162..406d1e34165f 100644 --- a/user_guide_src/source/changelogs/v4.7.1.rst +++ b/user_guide_src/source/changelogs/v4.7.1.rst @@ -56,6 +56,7 @@ Bugs Fixed - **Session:** Fixed a bug in ``MemcachedHandler`` where the constructor incorrectly threw an exception when ``savePath`` was not empty. - **Toolbar:** Fixed a bug where the standalone toolbar page loaded from ``?debugbar_time=...`` was not interactive. - **Toolbar:** Fixed a bug in the Routes panel where only the first route parameter was converted to an input field on hover. +- **Testing:** Fixed a bug in ``FeatureTestTrait::withRoutes()`` where invalid HTTP methods were not properly validated, thus passing them all to ``RouteCollection``. - **View:** Fixed a bug where ``View`` would throw an error if the ``appOverridesFolder`` config property was not defined. See the repo's