Skip to content

Commit

Permalink
Merge pull request #12586 from cakephp/bugfix/ext
Browse files Browse the repository at this point in the history
Fix silencing errors in extension handling.
  • Loading branch information
dereuromark committed Oct 3, 2018
2 parents b5c0db7 + 6d72604 commit c7c772b
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 18 deletions.
7 changes: 6 additions & 1 deletion src/Controller/Component/RequestHandlerComponent.php
Expand Up @@ -21,6 +21,7 @@
use Cake\Core\Configure;
use Cake\Core\Exception\Exception;
use Cake\Event\Event;
use Cake\Http\Exception\NotFoundException;
use Cake\Http\Response;
use Cake\Routing\Router;
use Cake\Utility\Exception\XmlException;
Expand Down Expand Up @@ -320,6 +321,7 @@ public function beforeRedirect(Event $event, $url, Response $response)
*
* @param \Cake\Event\Event $event The Controller.beforeRender event.
* @return bool false if the render process should be aborted
* @throws \Cake\Http\Exception\NotFoundException If invoked extension is not configured.
*/
public function beforeRender(Event $event)
{
Expand All @@ -332,8 +334,11 @@ public function beforeRender(Event $event)
!in_array($this->ext, ['html', 'htm']) &&
$response->getMimeType($this->ext)
);
if ($this->ext && !$isRecognized) {
throw new NotFoundException('Invoked extension not recognized/configured: ' . $this->ext);
}

if ($this->ext && $isRecognized) {
if ($this->ext) {
$this->renderAs($controller, $this->ext);
$response = $controller->response;
} else {
Expand Down
18 changes: 17 additions & 1 deletion src/Http/Response.php
Expand Up @@ -1111,7 +1111,7 @@ public function type($contentType = null)
{
deprecationWarning(
'Response::type() is deprecated. ' .
'Use getType() or withType() instead.'
'Use setTypeMap(), getType() or withType() instead.'
);

if ($contentType === null) {
Expand All @@ -1137,6 +1137,22 @@ public function type($contentType = null)
return $contentType;
}

/**
* Sets a content type definition into the map.
*
* E.g.: setTypeMap('xhtml', ['application/xhtml+xml', 'application/xhtml'])
*
* This is needed for RequestHandlerComponent and recognition of types.
*
* @param string $type Content type.
* @param string|array $mimeType Definition of the mime type.
* @return void
*/
public function setTypeMap($type, $mimeType)
{
$this->_mimeTypes[$type] = $mimeType;
}

/**
* Returns the current content type.
*
Expand Down
38 changes: 22 additions & 16 deletions tests/TestCase/Controller/Component/RequestHandlerComponentTest.php
Expand Up @@ -20,6 +20,7 @@
use Cake\Http\Response;
use Cake\Http\ServerRequest;
use Cake\Routing\DispatcherFactory;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\TestSuite\TestCase;
use Cake\View\AjaxView;
Expand All @@ -35,15 +36,11 @@ class RequestHandlerComponentTest extends TestCase
{

/**
* Controller property
*
* @var RequestHandlerTestController
*/
public $Controller;

/**
* RequestHandler property
*
* @var RequestHandlerComponent
*/
public $RequestHandler;
Expand Down Expand Up @@ -90,7 +87,7 @@ protected function _init()
$this->RequestHandler = $this->Controller->components()->load('RequestHandler');
$this->request = $request;

Router::scope('/', function ($routes) {
Router::scope('/', function (RouteBuilder $routes) {
$routes->setExtensions('json');
$routes->fallbacks('InflectedRoute');
});
Expand Down Expand Up @@ -383,7 +380,6 @@ public function testViewClassMapMethod()
{
$this->deprecated(function () {
$this->RequestHandler->setConfig(['viewClassMap' => ['json' => 'CustomJson']]);
$this->RequestHandler->initialize([]);
$result = $this->RequestHandler->viewClassMap();
$expected = [
'json' => 'CustomJson',
Expand Down Expand Up @@ -416,7 +412,6 @@ public function testIsAjaxParams()
{
$this->Controller->request = $this->request->withHeader('X-Requested-With', 'XMLHttpRequest');
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->Controller->beforeFilter($event);
$this->RequestHandler->startup($event);
$this->assertTrue($this->Controller->request->getParam('isAjax'));
Expand All @@ -432,7 +427,6 @@ public function testAutoAjaxLayout()
{
$event = new Event('Controller.startup', $this->Controller);
$this->Controller->request = $this->request->withHeader('X-Requested-With', 'XMLHttpRequest');
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$event = new Event('Controller.beforeRender', $this->Controller);
$this->RequestHandler->beforeRender($event);
Expand All @@ -443,7 +437,6 @@ public function testAutoAjaxLayout()

$this->_init();
$this->Controller->request = $this->Controller->request->withParam('_ext', 'js');
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$this->assertNotEquals(AjaxView::class, $this->Controller->viewBuilder()->getClassName());
}
Expand All @@ -459,7 +452,6 @@ public function testJsonViewLoaded()
Router::extensions(['json', 'xml', 'ajax'], false);
$this->Controller->request = $this->Controller->request->withParam('_ext', 'json');
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$event = new Event('Controller.beforeRender', $this->Controller);
$this->RequestHandler->beforeRender($event);
Expand All @@ -480,7 +472,6 @@ public function testXmlViewLoaded()
Router::extensions(['json', 'xml', 'ajax'], false);
$this->Controller->request = $this->Controller->request->withParam('_ext', 'xml');
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$event = new Event('Controller.beforeRender', $this->Controller);
$this->RequestHandler->beforeRender($event);
Expand All @@ -501,7 +492,6 @@ public function testAjaxViewLoaded()
Router::extensions(['json', 'xml', 'ajax'], false);
$this->Controller->request = $this->Controller->request->withParam('_ext', 'ajax');
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$event = new Event('Controller.beforeRender', $this->Controller);
$this->RequestHandler->beforeRender($event);
Expand All @@ -521,7 +511,6 @@ public function testNoViewClassExtension()
Router::extensions(['json', 'xml', 'ajax', 'csv'], false);
$this->Controller->request = $this->Controller->request->withParam('_ext', 'csv');
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$this->Controller->getEventManager()->on('Controller.beforeRender', function () {
return $this->Controller->response;
Expand All @@ -531,6 +520,26 @@ public function testNoViewClassExtension()
$this->assertEquals('csv', $this->Controller->viewBuilder()->getLayoutPath());
}

/**
* Tests that configured extensions that have no configured mimetype do not silently fallback to HTML.
*
* @return void
* @expectedException \Cake\Http\Exception\NotFoundException
* @expectedExceptionMessage Invoked extension not recognized/configured: foo
*/
public function testUnrecognizedExtensionFailure()
{
Router::extensions(['json', 'foo'], false);
$this->Controller->setRequest($this->Controller->getRequest()->withParam('_ext', 'foo'));
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->startup($event);
$this->Controller->getEventManager()->on('Controller.beforeRender', function () {
return $this->Controller->getResponse();
});
$this->Controller->render();
$this->assertEquals('RequestHandlerTest' . DS . 'csv', $this->Controller->viewBuilder()->getTemplatePath());
}

/**
* testStartupCallback method
*
Expand Down Expand Up @@ -799,7 +808,6 @@ public function testBeforeRedirectDisabled()
$this->Controller->request = $this->Controller->request->withHeader('X-Requested-With', 'XMLHttpRequest');

$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->RequestHandler->setConfig('enableBeforeRedirect', false);
$this->RequestHandler->startup($event);
$this->assertNull($this->RequestHandler->beforeRedirect($event, '/posts/index', $this->Controller->response));
Expand All @@ -816,7 +824,6 @@ public function testNonAjaxRedirect()
{
$this->deprecated(function () {
$event = new Event('Controller.startup', $this->Controller);
$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$this->assertNull($this->RequestHandler->beforeRedirect($event, '/', $this->Controller->response));
});
Expand All @@ -839,7 +846,6 @@ public function testAjaxRedirectWithNoUrl()
$this->Controller->response->expects($this->never())
->method('body');

$this->RequestHandler->initialize([]);
$this->RequestHandler->startup($event);
$this->assertNull($this->RequestHandler->beforeRedirect($event, null, $this->Controller->response));
});
Expand Down
24 changes: 24 additions & 0 deletions tests/TestCase/Http/ResponseTest.php
Expand Up @@ -265,6 +265,30 @@ public function testGetType()
);
}

/**
* @return void
*/
public function testSetTypeMap()
{
$response = new Response();
$response->setTypeMap('ical', 'text/calendar');

$response = $response->withType('ical')->getType();
$this->assertEquals('text/calendar', $response);
}

/**
* @return void
*/
public function testSetTypeMapAsArray()
{
$response = new Response();
$response->setTypeMap('ical', ['text/calendar']);

$response = $response->withType('ical')->getType();
$this->assertEquals('text/calendar', $response);
}

/**
* Tests the withType method
*
Expand Down

0 comments on commit c7c772b

Please sign in to comment.