diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php index 8b6e204bc3a..fd90a6d9ed5 100644 --- a/lib/Cake/Controller/Component/RequestHandlerComponent.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -144,6 +144,9 @@ public function initialize(Controller $controller) { * Compares the accepted types and configured extensions. * If there is one common type, that is assigned as the ext/content type * for the response. + * Type with the highest weight will be set. If the highest weight has more + * then one type matching the extensions, the order in which extensions are specified + * determines which type will be set. * * If html is one of the preferred types, no content type will be set, this * is to avoid issues with browsers that prefer html and several other content types. @@ -155,13 +158,19 @@ protected function _setExtension() { if (empty($accept)) { return; } + + $accepts = $this->response->mapType($this->request->parseAccept()); + $preferedTypes = current($accepts); + if (array_intersect($preferedTypes, array('html', 'xhtml'))) { + return null; + } + $extensions = Router::extensions(); - $preferred = array_shift($accept); - $preferredTypes = $this->response->mapType($preferred); - if (!in_array('xhtml', $preferredTypes) && !in_array('html', $preferredTypes)) { - $similarTypes = array_intersect($extensions, $preferredTypes); - if (count($similarTypes) === 1) { - $this->ext = array_shift($similarTypes); + foreach ($accepts as $types) { + $ext = array_intersect($extensions, $types); + if ($ext) { + $this->ext = current($ext); + break; } } } diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php index 769effe0517..05d9a5d6294 100644 --- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php @@ -229,7 +229,10 @@ public function testInitializeNoContentTypeWithSingleAccept() { } /** - * Test that ext is not set with multiple accepted content types. + * Test that ext is set to the first listed extension with multiple accepted + * content types. + * Having multiple types accepted with same weight, means the client lets the + * server choose the returned content type. * * @return void */ @@ -239,7 +242,27 @@ public function testInitializeNoContentTypeWithMultipleAcceptedTypes() { Router::parseExtensions('xml', 'json'); $this->RequestHandler->initialize($this->Controller); + $this->assertEquals('xml', $this->RequestHandler->ext); + + $this->RequestHandler->ext = null; + Router::setExtensions(array('json', 'xml'), false); + + $this->RequestHandler->initialize($this->Controller); + $this->assertEquals('json', $this->RequestHandler->ext); + } + +/** + * Test that ext is set to type with highest weight + * + * @return void + */ + public function testInitializeContentTypeWithMultipleAcceptedTypes() { + $_SERVER['HTTP_ACCEPT'] = 'text/csv;q=1.0, application/json;q=0.8, application/xml;q=0.7'; $this->assertNull($this->RequestHandler->ext); + Router::parseExtensions('xml', 'json'); + + $this->RequestHandler->initialize($this->Controller); + $this->assertEquals('json', $this->RequestHandler->ext); } /**