-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
NotFoundException is using the error500 template instead of the error400 template. #17599
Comments
Any idea which change it would be? 5.0.4...5.0.5 |
My best guess is the ErrorHandlerMiddleware, but I don't know enough about the Middleware internals to know for sure. I'll dump a trace for you. Maybe it'll give a clue. 5.0.4...5.0.5#diff-aff0c9a62d0ee25e99d5331845f5bceddbad2223546c1c4fdc97f4f85feb7359R149
|
The Edit: To add, this is just 1 example. Every Cake\Http\Exception\NotFoundException 404 error is doing this in the unit tests. This is the full <?php
declare(strict_types=1);
namespace App\Policy;
use App\Controller\AppController;
use Authorization\IdentityInterface;
use Authorization\Policy\BeforePolicyInterface;
use Authorization\Policy\ResultInterface;
use Cake\Core\Configure;
use Cake\Http\Exception\NotFoundException;
/**
* Base Controller policy
*/
class AppControllerPolicy implements BeforePolicyInterface
{
/**
* Summary of before
*
* @param ?\Authorization\IdentityInterface $identity The user or null
* @param mixed $resource The controller
* @param string $action The name of the action trying to be accessed
* @return \Authorization\Policy\ResultInterface|bool|null
* @throws \Cake\Http\Exception\NotFoundException if the action doesn't exist.
*/
public function before(?IdentityInterface $identity, mixed $resource, string $action): ResultInterface|bool|null
{
// throw a 404 here for all missing actions.
if (!empty($action) && $resource instanceof AppController) {
if (!method_exists($resource, $action)) {
$message = __('Page Not Found');
if (Configure::read('debug')) {
$message = __('Missing Action `{0}::{1}()`', [
get_class($resource),
$action,
]);
}
throw new NotFoundException($message);
}
}
// fall through
// always return null so that the other, more specific policy checks can happen.
return null;
}
} These traces are from the cli-error.log during unit testing This is with Debug on:
This is with Debug Off:
|
Could this be related to #17655 ? I am sure the core doesn't use such prefix error tests, so it went unnoticed. |
Yeah, that may be the issue, looking under a prefix. I'll go back, look at my code, and see if a prefix is what was causing it. |
Interesting. That was already in 4.5 |
So an update. It doesn't seem to be caused by prefixes or plugins as the PagesController is in the app, not in a plugin. The tests like so don't have prefixes in them: // tests/TestCase/Controller/PagesControllerTest.php
class PagesControllerTest extends BaseControllerTest
{
/**
* Test that missing template renders 404 page in production
*
* @return void
*/
public function testMissingTemplate()
{
Configure::write('debug', false); // being explicit here
$this->get('https://localhost/pages/not_existing');
$this->assertResponseCode(404);
$this->helperTestError400('/pages/not_existing'); <--- fails here
}
}
// tests/TestCase/Controller/BaseControllerTest.php
// this is just mainly helper functions to stay DRY.
// things like fixtures defined and helper functions like below.
// nothing that would invoke a change in the environment other than defining fixtures.
class BaseControllerTest extends TestCase
{
use IntegrationTestTrait;
/**
* Fixtures
*
* @var array<string>
*/
protected array $fixtures = [
'app.Users',
'app.Sources',
'app.Tags',
'app.QrCodes',
'app.QrImages',
'app.QrCodesTags',
];
/**
* @var \App\Model\Table\UsersTable
*/
public $Users;
//// other helper fuctions
/**
* Tests that we're using the Error/error400 page
*
* @param ?string $path If included, also look for the actual error path as well.
* @return void
*/
public function helperTestError400(?string $path = null): void
{
$this->helperTestLayoutError();
$content = (string)$this->_response->getBody();
/// It's using App.Error/error500
// I have a view helper that extends the Cake\View\Helper, and writes out the template being used.
// That helper is writing "<!-- START: App.Error/error500 -->" and using that template.
$this->assertSame(1, substr_count($content, '<!-- START: App.Error/error400 -->')); <--- Failing here.
$this->assertSame(1, substr_count($content, '<!-- END: App.Error/error400 -->'));
if ($path) {
$this->assertSame(1, substr_count($content, 'The requested address <strong>\'' . $path . '\'</strong> was not found.'));
}
// test other specific to this layout.
}
}
/// in src/View/Helper/TemplateHelper.php
/**
* Writes the template location coment.
*
* @param bool $start If were the start, or the end
* @param string $path Absolute path to the Template.
* @param string $prefix The prefix, mainly App, or a plugin identifier
* @return string
*/
public function templateComment(bool $start, string $path, string $prefix = 'App'): string
{
$comment = "\n\n" . '<!-- ' . ($start ? 'START' : 'END') . ': ' . $prefix . '.';
$path = str_replace(ROOT . DS . 'templates' . DS, '', $path);
$path = str_replace('.php', '', $path);
$comment .= $path . ' -->' . "\n\n";
return $comment;
}
// in templates/Error/error400.php, error500.php, and others.
use Cake\Core\Configure;
use Cake\Error\Debugger;
$this->layout = 'error';
?>
<?= $this->Template->templateComment(true, __FILE__); ?> With the same test above, but <body>
<header>
<h1 class="header-title">
<span>Template file <code>`Pages/not_existing.php`</code> could not be found.</span>
<a>📋</a>
</h1>
<span class="header-description"><br />
The following paths were searched:<br />
<br />
- <code>`[ROOT redacted]/templates/Pages/not_existing.php`</code><br />
- <code>`[ROOT redacted]/vendor/cakephp/cakephp/templates/Pages/not_existing.php`</code></span>
<span class="header-type">Cake\View\Exception\MissingTemplateException</span>
</header> It was definitely as change from version I would submit a patch/tests/PR, but I can't seem what would be causing it. If it helps, I can make my git repo plublic, or give one of you access to it. |
Here is the stack traces from the log file if it helps: This is the stack trace from debug turned off:
And the same with debug turned on
|
Here is the <?php
declare(strict_types=1);
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 0.2.9
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace App\Controller;
use Cake\Core\Configure;
use Cake\Event\EventInterface;
use Cake\Http\Exception\ForbiddenException;
use Cake\Http\Exception\NotFoundException;
use Cake\Http\Response;
use Cake\View\Exception\MissingTemplateException;
/**
* Static content controller
*
* This controller will render views from templates/Pages/
*
* @link https://book.cakephp.org/4/en/controllers/pages-controller.html
*/
class PagesController extends AppController
{
/**
* Runs before the code in the actions
*
* @return void
*/
public function beforeFilter(EventInterface $event): void
{
$this->Authentication->addUnauthenticatedActions(['display']);
parent::beforeFilter($event);
}
/**
* Displays a view
*
* @param string ...$path Path segments.
* @return \Cake\Http\Response|null
* @throws \Cake\Http\Exception\ForbiddenException When a directory traversal attempt.
* @throws \Cake\View\Exception\MissingTemplateException When the view file could not
* be found and in debug mode.
* @throws \Cake\Http\Exception\NotFoundException When the view file could not
* be found and not in debug mode.
* @throws \Cake\View\Exception\MissingTemplateException In debug mode.
*/
public function display(string ...$path): ?Response
{
$activeUser = $this->getActiveUser();
if (!$path) {
return $this->redirect('/');
}
if (in_array('..', $path, true) || in_array('.', $path, true)) {
throw new ForbiddenException();
}
$page = $subpage = null;
if (!empty($path[0])) {
$page = $path[0];
}
if (!empty($path[1])) {
$subpage = $path[1];
}
$this->set(compact('page', 'subpage', 'activeUser'));
try {
return $this->render(implode('/', $path));
} catch (MissingTemplateException $exception) {
if (Configure::read('debug')) {
throw $exception;
}
throw new NotFoundException();
}
}
} |
I'm wondering if it could be due to how I'm using the new Policy stuff? // src/Policy/AppControllerPolicy.php
<?php
declare(strict_types=1);
namespace App\Policy;
use App\Controller\AppController;
use Authorization\IdentityInterface;
use Authorization\Policy\BeforePolicyInterface;
use Authorization\Policy\ResultInterface;
use Cake\Core\Configure;
use Cake\Http\Exception\NotFoundException;
/**
* Base Controller policy
*/
class AppControllerPolicy implements BeforePolicyInterface
{
/**
* Summary of before
*
* @param ?\Authorization\IdentityInterface $identity The user or null
* @param mixed $resource The controller
* @param string $action The name of the action trying to be accessed
* @return \Authorization\Policy\ResultInterface|bool|null
* @throws \Cake\Http\Exception\NotFoundException if the action doesn't exist.
*/
public function before(?IdentityInterface $identity, mixed $resource, string $action): ResultInterface|bool|null
{
// throw a 404 here for all missing actions.
if (!empty($action) && $resource instanceof AppController) {
if (!method_exists($resource, $action)) {
$message = __('Page Not Found');
if (Configure::read('debug')) {
$message = __('Missing Action `{0}::{1}()`', [
get_class($resource),
$action,
]);
}
throw new NotFoundException($message);
}
}
// fall through
// always return null so that the other, more specific policy checks can happen.
return null;
}
} // src/Policy/PagesControllerPolicy.php
<?php
declare(strict_types=1);
namespace App\Policy;
use App\Controller\PagesController;
use App\Model\Entity\User;
/**
* Pages Controller policy
*/
class PagesControllerPolicy extends AppControllerPolicy
{
/**
* Anyone can view pages.
*
* @param \App\Model\Entity\User|null $user The identity object.
* @param \App\Controller\PagesController $PagesController
* @return bool
*/
public function canDisplay(?User $user, PagesController $PagesController): bool
{
return true;
}
} |
Here is my <?php
declare(strict_types=1);
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 3.3.0
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace App;
use App\Controller\Admin\QrCodesController as AdminQrCodesController;
use App\Controller\Admin\QrImagesController as AdminQrImagesController;
use App\Controller\Admin\SourcesController as AdminSourcesController;
use App\Controller\Admin\TagsController as AdminTagsController;
use App\Controller\Admin\UsersController as AdminUsersController;
use App\Controller\PagesController;
use App\Controller\QrCodesController;
use App\Controller\QrImagesController;
use App\Controller\TagsController;
use App\Controller\UsersController;
use App\Event\QrCodeListener;
use App\Policy\Admin\QrCodesControllerPolicy as AdminQrCodesControllerPolicy;
use App\Policy\Admin\QrImagesControllerPolicy as AdminQrImagesControllerPolicy;
use App\Policy\Admin\SourcesControllerPolicy as AdminSourcesControllerPolicy;
use App\Policy\Admin\TagsControllerPolicy as AdminTagsControllerPolicy;
use App\Policy\Admin\UsersControllerPolicy as AdminUsersControllerPolicy;
use App\Policy\PagesControllerPolicy;
use App\Policy\QrCodesControllerPolicy;
use App\Policy\QrImagesControllerPolicy;
use App\Policy\TagsControllerPolicy;
use App\Policy\UsersControllerPolicy;
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Identifier\AbstractIdentifier;
use Authentication\Middleware\AuthenticationMiddleware;
use Authorization\AuthorizationService;
use Authorization\AuthorizationServiceInterface;
use Authorization\AuthorizationServiceProviderInterface;
use Authorization\Exception\ForbiddenException;
use Authorization\Exception\MissingIdentityException;
use Authorization\Middleware\AuthorizationMiddleware;
use Authorization\Policy\MapResolver;
use Authorization\Policy\OrmResolver;
use Authorization\Policy\ResolverCollection;
use Cake\Core\Configure;
use Cake\Core\ContainerInterface;
use Cake\Datasource\FactoryLocator;
use Cake\Error\Middleware\ErrorHandlerMiddleware;
use Cake\Http\BaseApplication;
use Cake\Http\Middleware\BodyParserMiddleware;
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\Middleware\HttpsEnforcerMiddleware;
use Cake\Http\Middleware\SecurityHeadersMiddleware;
use Cake\Http\MiddlewareQueue;
use Cake\ORM\Locator\TableLocator;
use Cake\Routing\Middleware\AssetMiddleware;
use Cake\Routing\Middleware\RoutingMiddleware;
use Cake\Routing\Router;
use Psr\Http\Message\ServerRequestInterface;
/**
* Application setup class.
*
* This defines the bootstrapping logic and middleware layers you
* want to use in your application.
*
* @extends \Cake\Http\BaseApplication<\App\Application>
*/
class Application extends BaseApplication implements
AuthenticationServiceProviderInterface,
AuthorizationServiceProviderInterface
{
/**
* Load all the application configuration and bootstrap logic.
*
* @return void
*/
public function bootstrap(): void
{
// Call parent to load bootstrap from files.
parent::bootstrap();
if (PHP_SAPI === 'cli') {
$this->bootstrapCli();
}
FactoryLocator::add(
'Table',
(new TableLocator())->allowFallbackClass(false)
);
/*
* Only try to load DebugKit in development mode
* Debug Kit should not be installed on a production system
*/
if (Configure::read('debug') && !$this->getPlugins()->has('DebugKit')) {
$this->addOptionalPlugin('DebugKit');
}
// Load more plugins here
if (!$this->getPlugins()->has('Authentication')) {
$this->addPlugin('Authentication');
}
// CakePHP's Authorization Plugin.
if (!$this->getPlugins()->has('Authorization')) {
$this->addPlugin('Authorization');
}
// the friendsofcake/bootstrapui plugin.
if (!$this->getPlugins()->has('BootstrapUI')) {
$this->addPlugin('BootstrapUI');
}
// the friendsofcake/bootstrapui plugin.
if (!$this->getPlugins()->has('Search')) {
$this->addPlugin('Search');
}
// my stats plugin
if (!$this->getPlugins()->has('Fr3nch13/Stats')) {
$this->addPlugin('Fr3nch13/Stats');
}
// register the event listeners.
$this->registerEventListeners();
}
/**
* Setup the middleware queue your application will use.
*
* @param \Cake\Http\MiddlewareQueue $middlewareQueue The middleware queue to setup.
* @return \Cake\Http\MiddlewareQueue The updated middleware queue.
*/
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
// Catch any exceptions in the lower layers,
// and make an error page/response
->add(new ErrorHandlerMiddleware(Configure::read('Error'), $this))
// Handle plugin/theme assets like CakePHP normally does.
->add(new AssetMiddleware([
'cacheTime' => Configure::read('Asset.cacheTime'),
]))
// Add routing middleware.
// If you have a large number of routes connected, turning on routes
// caching in production could improve performance.
// See https://github.com/CakeDC/cakephp-cached-routing
->add(new RoutingMiddleware($this))
// Parse various types of encoded request bodies so that they are
// available as array through $request->getData()
// https://book.cakephp.org/4/en/controllers/middleware.html#body-parser-middleware
->add(new BodyParserMiddleware())
// Cross Site Request Forgery (CSRF) Protection Middleware
// https://book.cakephp.org/4/en/security/csrf.html#cross-site-request-forgery-csrf-middleware
->add(new CsrfProtectionMiddleware([
'httponly' => true,
]))
// @link https://book.cakephp.org/5/en/tutorials-and-examples/cms/authentication.html
->add(new AuthenticationMiddleware($this))
// @link https://book.cakephp.org/5/en/tutorials-and-examples/cms/authorization.html
->add(new AuthorizationMiddleware($this, [
'requireAuthorizationCheck' => false,
'identityDecorator' => function ($auth, $user) {
return $user->setAuthorization($auth); //turns the user entity directly into the identity object.
},
'unauthorizedHandler' => [
'className' => 'CustomRedirect',
'url' => Router::url('/admin', true),
'queryParam' => 'redirect',
'exceptions' => [
MissingIdentityException::class,
ForbiddenException::class,
],
'custom_param' => true,
],
]));
/*
// TODO: Enable when whatever unsafe-inline is fixed.
// It's causing inline onclicks to be blocked, even though unsafe-inline is set to true.
// Content Security Policy
// @link https://book.cakephp.org/5/en/security/content-security-policy.html#content-security-policy-middleware
// @link https://github.com/paragonie/csp-builder
->add(new CspMiddleware([
'script-src' => [
'self' => true,
'unsafe-inline' => true,
'unsafe-eval' => false,
'allow' => [
// external domains that can load/run javascript.
//'https://www.google-analytics.com',
],
],
], [
'scriptNonce' => true,
'styleNonce' => true,
]))
*/
// @link https://book.cakephp.org/5/en/security/security-headers.html
$securityHeaders = new SecurityHeadersMiddleware();
$securityHeaders
->setReferrerPolicy()
->setXFrameOptions()
->noOpen()
->noSniff();
$middlewareQueue->add($securityHeaders);
$https = new HttpsEnforcerMiddleware([
'redirect' => true,
'statusCode' => 302,
'disableOnDebug' => true,
'hsts' => [
// How long the header value should be cached for.
'maxAge' => 60 * 60 * 24 * 365,
// should this policy apply to subdomains?
'includeSubDomains' => true,
// Should the header value be cacheable in google's HSTS preload
// service? While not part of the spec it is widely implemented.
'preload' => true,
],
]);
$middlewareQueue->add($https);
return $middlewareQueue;
}
/**
* Register application container services.
*
* @param \Cake\Core\ContainerInterface $container The Container to update.
* @return void
* @link https://book.cakephp.org/4/en/development/dependency-injection.html#dependency-injection
*/
public function services(ContainerInterface $container): void
{
}
/**
* Gets and Configures the Authentication Service
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @return \Authentication\AuthenticationServiceInterface
*/
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$fields = [
AbstractIdentifier::CREDENTIAL_USERNAME => 'email',
AbstractIdentifier::CREDENTIAL_PASSWORD => 'password',
];
$authenticationService = new AuthenticationService([
'unauthenticatedRedirect' => Router::url([
'prefix' => false,
'plugin' => false,
'controller' => 'Users',
'action' => 'login',
]),
'queryParam' => 'redirect',
]);
// Load identifiers, ensure we check email and password fields
$authenticationService->loadIdentifier('Authentication.Password', [
'fields' => $fields,
'resolver' => [
'className' => 'Authentication.Orm',
'userModel' => 'Users',
'finder' => 'active',
],
]);
// Load the authenticators, you want session first
$authenticationService->loadAuthenticator('Authentication.Session');
// Configure form data check to pick email and password
$authenticationService->loadAuthenticator('Authentication.Form', [
'fields' => $fields,
'loginUrl' => [
Router::url([
'prefix' => false,
'plugin' => false,
'controller' => 'Users',
'action' => 'login',
'_ext' => null,
]),
Router::url([
'prefix' => false,
'plugin' => false,
'controller' => 'Users',
'action' => 'login',
'_ext' => 'json',
]),
],
]);
// Used for Remember me
$authenticationService->loadAuthenticator('Authentication.Cookie', [
'fields' => $fields,
'loginUrl' => [
Router::url([
'prefix' => false,
'plugin' => false,
'controller' => 'Users',
'action' => 'login',
'_ext' => null,
]),
Router::url([
'prefix' => false,
'plugin' => false,
'controller' => 'Users',
'action' => 'login',
'_ext' => 'json',
]),
],
]);
return $authenticationService;
}
/**
* Gets the Authorization Service
*
* @param \Psr\Http\Message\ServerRequestInterface $request
* @return \Authorization\AuthorizationServiceInterface
*/
public function getAuthorizationService(ServerRequestInterface $request): AuthorizationServiceInterface
{
// Use the Map Resolver to map controllers to a policy.
$mapResolver = new MapResolver();
// map the controllers
$mapResolver->map(QrCodesController::class, QrCodesControllerPolicy::class);
$mapResolver->map(QrImagesController::class, QrImagesControllerPolicy::class);
$mapResolver->map(TagsController::class, TagsControllerPolicy::class);
$mapResolver->map(UsersController::class, UsersControllerPolicy::class);
$mapResolver->map(PagesController::class, PagesControllerPolicy::class);
// admin controllers
$mapResolver->map(AdminQrCodesController::class, AdminQrCodesControllerPolicy::class);
$mapResolver->map(AdminQrImagesController::class, AdminQrImagesControllerPolicy::class);
$mapResolver->map(AdminSourcesController::class, AdminSourcesControllerPolicy::class);
$mapResolver->map(AdminTagsController::class, AdminTagsControllerPolicy::class);
$mapResolver->map(AdminUsersController::class, AdminUsersControllerPolicy::class);
$ormResolver = new OrmResolver();
// @link https://book.cakephp.org/authorization/3/en/policy-resolvers.html#using-multiple-resolvers
$resolver = new ResolverCollection([
// make sure this one is first.
// we want to check the general controller actions,
$mapResolver,
// before we check the individual entities,
// or scopes for index pages.
$ormResolver,
]);
return new AuthorizationService($resolver);
}
/**
* Register event listeners globally.
*
* Called in self::bootstrap()
*
* @return void
*/
protected function registerEventListeners(): void
{
/** @var \Cake\Event\EventManager $eventManager */
$eventManager = $this->getEventManager();
// make sure they're only getting registered globally, once.
// TODO: Hacky as we're tracking the event key, not if the listener itself is already registered.
// Maybe use listeners('QrCode.onHit')
if (empty($eventManager->prioritisedListeners('QrCode.onHit'))) {
$eventManager->on(new QrCodeListener());
}
}
/**
* Bootstrapping for CLI application.
*
* That is when running commands.
*
* @return void
*/
protected function bootstrapCli(): void
{
if (!$this->getPlugins()->has('Bake')) {
$this->addOptionalPlugin('Bake');
}
if (!$this->getPlugins()->has('Migrations')) {
$this->addPlugin('Migrations');
}
// Load more plugins here
}
} |
Have you tried not loading the authentication/authorizations plugin to see if that resolves the problem?
Curious that the stack traces are different, and that in debug mode you get to view rendering, while with debug off it is the controller action that is raising an exception. |
I haven't, but I will.
Probably because of right here in the /**
* Displays a view
*
* @param string ...$path Path segments.
* @return \Cake\Http\Response|null
* @throws \Cake\Http\Exception\ForbiddenException When a directory traversal attempt.
* @throws \Cake\View\Exception\MissingTemplateException When the view file could not
* be found and in debug mode.
* @throws \Cake\Http\Exception\NotFoundException When the view file could not
* be found and not in debug mode.
* @throws \Cake\View\Exception\MissingTemplateException In debug mode.
*/
public function display(string ...$path): ?Response
{
$activeUser = $this->getActiveUser();
if (!$path) {
return $this->redirect('/');
}
if (in_array('..', $path, true) || in_array('.', $path, true)) {
throw new ForbiddenException();
}
$page = $subpage = null;
if (!empty($path[0])) {
$page = $path[0];
}
if (!empty($path[1])) {
$subpage = $path[1];
}
$this->set(compact('page', 'subpage', 'activeUser'));
try {
return $this->render(implode('/', $path));
} catch (MissingTemplateException $exception) {
if (Configure::read('debug')) {
throw $exception; <---- HERE With Debug on, a 500
}
throw new NotFoundException(); <---- AND HERE a 404, but uses error500.php instead of error400.php
}
} |
Weird. I disable Authentication and Authorization and these specific tests pass: // tests/TestCase/Controller/PagesControllerTest.php
/**
* Test that missing template renders 404 page in production
*
* @return void
*/
public function testMissingTemplate()
{
Configure::write('debug', false);
$this->get('https://localhost/pages/not_existing');
$this->assertResponseCode(404);
$this->helperTestError400('/pages/not_existing'); <--- Testing for error400.php , and passing.
}
/**
* Test that missing template in debug mode renders missing_template error page
*
* @return void
*/
public function testMissingTemplateInDebug()
{
Configure::write('debug', true);
$this->get('https://localhost/pages/not_existing');
$this->assertResponseCode(500);
$this->assertResponseContains('Missing Template');
$this->assertResponseContains('stack-frames');
$this->assertResponseContains('not_existing.php');
} I wonder why with Auths integrated, why is would change |
Screw it, I'm just going to make this project public, since it's a personal site I created to track QR codes: https://github.com/fr3nch13/qr.fr3nch.com It's a new app, that started on CakePHP 5 as a way to learn the new changes to 5.x. And also give me a way to make and track QR codes I've printed in the wild. Its code coverage is over 97%. |
So, maybe I found it, but I still don't know what change between 5.0.4 and 5.0.5 would've caused it.
But that method hasn't changed. It's called by the It all seems to come down to this chunk right here: |
One interesting thing... At https://github.com/cakephp/cakephp/blob/5.0.4/src/Error/Renderer/WebExceptionRenderer.php#L412 try {
print_r(get_class($this->controller));
print_r($template);
$this->controller->render($template);
return $this->_shutdown();
} catch (MissingTemplateException $e) { I get
but in https://github.com/cakephp/cakephp/blob/5.0.5/src/Error/Renderer/WebExceptionRenderer.php#L411
Here is my ErrorController.php https://github.com/fr3nch13/qr.fr3nch.com/blob/main/src/Controller/ErrorController.php <?php
declare(strict_types=1);
/**
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
* @link https://cakephp.org CakePHP(tm) Project
* @since 3.3.4
* @license https://opensource.org/licenses/mit-license.php MIT License
*/
namespace App\Controller;
use Cake\Event\EventInterface;
/**
* Error Handling Controller
*
* Controller used by ExceptionRenderer to render error responses.
*/
class ErrorController extends AppController
{
/**
* beforeRender callback.
*
* @param \Cake\Event\EventInterface<\Cake\Controller\Controller> $event Event.
* @return void
*/
public function beforeRender(EventInterface $event): void
{
parent::beforeRender($event);
$this->viewBuilder()->setTemplatePath('Error'); <--- Here
}
} |
This could be the problem, do you have any components like Authorization or Authentication? Both of these plugins can raise exceptions during exception rendering which counts as a 500 to the framework. |
Description
I noticed that something changed between 5.04 and 5.05 that is now causing the
\Cake\Http\Exception\NotFoundException
to use the error500 template instead of the error400 template, at least in my unit tests. I have confirmed the error message that is associated with the specific 404 error is there, it's just using the wrong template.I would open a PR, but I still haven't been able to track down exactly which part of the code changed, or if I have something in my code that could be causing this. I also went through the changeling between 5.04 and 5.05, and didn't see anything that stood out that would cause this.
As a background, this is a new application, written only on CakePHP 5, so it's not ported from 4.x
CakePHP Version
5.04 ... 5.05
PHP Version
8.2.14
The text was updated successfully, but these errors were encountered: