Fix an infinite recursion caused by missing plugin

When a MissingPluginException has caught when rendering an exception,
we should disable the plugin as needed to prevent an infinite recursion.
This commit is contained in:
chinpei215 2014-07-09 02:47:01 +09:00
parent b3dfad614a
commit 0c1fc36b14
3 changed files with 84 additions and 0 deletions

View file

@ -285,6 +285,12 @@ class ExceptionRenderer {
} else {
$this->_outputMessage('error500');
}
} catch (MissingPluginException $e) {
$attributes = $e->getAttributes();
if (isset($attributes['plugin']) && $attributes['plugin'] === $this->controller->plugin) {
$this->controller->plugin = null;
}
$this->_outputMessageSafe('error500');
} catch (Exception $e) {
$this->_outputMessageSafe('error500');
}

View file

@ -764,6 +764,73 @@ class ExceptionRendererTest extends CakeTestCase {
$this->assertEquals('Errors', $ExceptionRenderer->controller->viewPath);
}
/**
* Test that missing plugin disables Controller::$plugin if the two are the same plugin.
*
* @return void
*/
public function testMissingPluginRenderSafe() {
$exception = new NotFoundException();
$ExceptionRenderer = new ExceptionRenderer($exception);
$ExceptionRenderer->controller = $this->getMock('Controller', array('render'));
$ExceptionRenderer->controller->plugin = 'TestPlugin';
$ExceptionRenderer->controller->request = $this->getMock('CakeRequest');
$exception = new MissingPluginException(array('plugin' => 'TestPlugin'));
$ExceptionRenderer->controller->expects($this->once())
->method('render')
->with('error400')
->will($this->throwException($exception));
$response = $this->getMock('CakeResponse');
$response->expects($this->once())
->method('body')
->with($this->logicalAnd(
$this->logicalNot($this->stringContains('test plugin error500')),
$this->stringContains('Not Found')
));
$ExceptionRenderer->controller->response = $response;
$ExceptionRenderer->render();
}
/**
* Test that missing plugin doesn't disable Controller::$plugin if the two aren't the same plugin.
*
* @return void
*/
public function testMissingPluginRenderSafeWithPlugin() {
App::build(array(
'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
), App::RESET);
CakePlugin::load('TestPlugin');
$exception = new NotFoundException();
$ExceptionRenderer = new ExceptionRenderer($exception);
$ExceptionRenderer->controller = $this->getMock('Controller', array('render'));
$ExceptionRenderer->controller->plugin = 'TestPlugin';
$ExceptionRenderer->controller->request = $this->getMock('CakeRequest');
$exception = new MissingPluginException(array('plugin' => 'TestPluginTwo'));
$ExceptionRenderer->controller->expects($this->once())
->method('render')
->with('error400')
->will($this->throwException($exception));
$response = $this->getMock('CakeResponse');
$response->expects($this->once())
->method('body')
->with($this->logicalAnd(
$this->stringContains('test plugin error500'),
$this->stringContains('Not Found')
));
$ExceptionRenderer->controller->response = $response;
$ExceptionRenderer->render();
CakePlugin::unload();
}
/**
* Test that exceptions can be rendered when an request hasn't been registered
* with Router

View file

@ -0,0 +1,11 @@
test plugin error500
<h2><?php echo $message; ?></h2>
<p class="error">
<strong><?php echo __d('cake', 'Error'); ?>: </strong>
<?php echo __d('cake', 'An Internal Error Has Occurred.'); ?>
</p>
<?php
if (Configure::read('debug') > 0):
echo $this->element('exception_stack_trace');
endif;
?>